Skip to content

Commit

Permalink
Adapt socket handling to support listening on multiple sockets
Browse files Browse the repository at this point in the history
    Introduce internal changes preparing the server to
    handle multiple sockets concurrently for both
    TCP and UDP protocols. While no user-visible
    features are implemented yet, these modifications
    are essential for enabling future functionality
    such as listening on multiple ports.

    Key changes are: converting link_socket from a
    single pointer to an array in various contexts,
    in order to be able to store multiple sockets
    at once.

Change-Id: Ia0a889e800f0b36aed770ee36e31afeec5df6084
Signed-off-by: Antonio Quartulli <[email protected]>
Signed-off-by: Gianmarco De Gregori <[email protected]>
Acked-by: Gert Doering <[email protected]>
Message-Id: <[email protected]>
URL: https://www.mail-archive.com/[email protected]/msg30309.html
Signed-off-by: Gert Doering <[email protected]>
  • Loading branch information
ordex authored and cron2 committed Dec 30, 2024
1 parent 10e785f commit 94b391d
Show file tree
Hide file tree
Showing 16 changed files with 320 additions and 177 deletions.
18 changes: 9 additions & 9 deletions src/openvpn/dco.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,11 +478,11 @@ dco_p2p_add_new_peer(struct context *c)
return 0;
}

struct link_socket *ls = c->c2.link_socket;
struct link_socket *sock = c->c2.link_sockets[0];

ASSERT(ls->info.connection_established);
ASSERT(sock->info.connection_established);

struct sockaddr *remoteaddr = &ls->info.lsa->actual.dest.addr.sa;
struct sockaddr *remoteaddr = &sock->info.lsa->actual.dest.addr.sa;
struct tls_multi *multi = c->c2.tls_multi;
#ifdef TARGET_FREEBSD
/* In Linux in P2P mode the kernel automatically removes an existing peer
Expand All @@ -494,7 +494,7 @@ dco_p2p_add_new_peer(struct context *c)
}
#endif
int ret = dco_new_peer(&c->c1.tuntap->dco, multi->peer_id,
c->c2.link_socket->sd, NULL, remoteaddr, NULL, NULL);
c->c2.link_sockets[0]->sd, NULL, remoteaddr, NULL, NULL);
if (ret < 0)
{
return ret;
Expand Down Expand Up @@ -527,12 +527,12 @@ dco_multi_get_localaddr(struct multi_context *m, struct multi_instance *mi,
#if ENABLE_IP_PKTINFO
struct context *c = &mi->context;

if (!proto_is_udp(c->c2.link_socket->info.proto) || !(c->options.sockflags & SF_USE_IP_PKTINFO))
if (!proto_is_udp(c->c2.link_sockets[0]->info.proto) || !(c->options.sockflags & SF_USE_IP_PKTINFO))
{
return false;
}

struct link_socket_actual *actual = &c->c2.link_socket_info->lsa->actual;
struct link_socket_actual *actual = &c->c2.link_socket_infos[0]->lsa->actual;

switch (actual->dest.addr.sa.sa_family)
{
Expand Down Expand Up @@ -577,7 +577,7 @@ dco_multi_add_new_peer(struct multi_context *m, struct multi_instance *mi)
int peer_id = c->c2.tls_multi->peer_id;
struct sockaddr *remoteaddr, *localaddr = NULL;
struct sockaddr_storage local = { 0 };
int sd = c->c2.link_socket->sd;
int sd = c->c2.link_sockets[0]->sd;


if (c->mode == CM_CHILD_TCP)
Expand All @@ -587,8 +587,8 @@ dco_multi_add_new_peer(struct multi_context *m, struct multi_instance *mi)
}
else
{
ASSERT(c->c2.link_socket_info->connection_established);
remoteaddr = &c->c2.link_socket_info->lsa->actual.dest.addr.sa;
ASSERT(c->c2.link_socket_infos[0]->connection_established);
remoteaddr = &c->c2.link_socket_infos[0]->lsa->actual.dest.addr.sa;
}

/* In server mode we need to fetch the remote addresses from the push config */
Expand Down
47 changes: 29 additions & 18 deletions src/openvpn/forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,17 @@ static const char *
wait_status_string(struct context *c, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc(64, gc);
buf_printf(&out, "I/O WAIT %s|%s|%s|%s %s",

buf_printf(&out, "I/O WAIT %s|%s| %s",
tun_stat(c->c1.tuntap, EVENT_READ, gc),
tun_stat(c->c1.tuntap, EVENT_WRITE, gc),
socket_stat(c->c2.link_socket, EVENT_READ, gc),
socket_stat(c->c2.link_socket, EVENT_WRITE, gc),
tv_string(&c->c2.timeval, gc));
for (int i = 0; i < c->c1.link_sockets_num; i++)
{
buf_printf(&out, "\n %s|%s",
socket_stat(c->c2.link_sockets[i], EVENT_READ, gc),
socket_stat(c->c2.link_sockets[i], EVENT_WRITE, gc));
}
return BSTR(&out);
}

Expand Down Expand Up @@ -99,7 +104,7 @@ check_tls_errors(struct context *c)
{
if (c->c2.tls_multi && c->c2.tls_exit_signal)
{
if (link_socket_connection_oriented(c->c2.link_socket))
if (link_socket_connection_oriented(c->c2.link_sockets[0]))
{
if (c->c2.tls_multi->n_soft_errors)
{
Expand Down Expand Up @@ -567,6 +572,7 @@ check_status_file(struct context *c)
#ifdef ENABLE_FRAGMENT
/*
* Should we deliver a datagram fragment to remote?
* c is expected to be a single-link context (p2p or child)
*/
static void
check_fragment(struct context *c)
Expand Down Expand Up @@ -1123,7 +1129,9 @@ process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, boo
decrypt_status = openvpn_decrypt(&c->c2.buf, c->c2.buffers->decrypt_buf,
co, &c->c2.frame, ad_start);

if (!decrypt_status && link_socket_connection_oriented(c->c2.link_socket))
if (!decrypt_status
/* on the instance context we have only one socket, so just check the first one */
&& link_socket_connection_oriented(c->c2.link_sockets[0]))
{
/* decryption errors are fatal in TCP mode */
register_signal(c->sig, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- decryption error in TCP mode */
Expand Down Expand Up @@ -1451,7 +1459,7 @@ drop_if_recursive_routing(struct context *c, struct buffer *buf)
*/

void
process_incoming_tun(struct context *c)
process_incoming_tun(struct context *c, struct link_socket *out_sock)
{
struct gc_arena gc = gc_new();

Expand Down Expand Up @@ -1484,7 +1492,7 @@ process_incoming_tun(struct context *c)
*/
unsigned int flags = PIPV4_PASSTOS | PIP_MSSFIX | PIPV4_CLIENT_NAT
| PIPV6_ICMP_NOHOST_CLIENT;
process_ip_header(c, flags, &c->c2.buf);
process_ip_header(c, flags, &c->c2.buf, out_sock);

#ifdef PACKET_TRUNCATION_CHECK
/* if (c->c2.buf.len > 1) --c->c2.buf.len; */
Expand Down Expand Up @@ -1645,7 +1653,8 @@ ipv6_send_icmp_unreachable(struct context *c, struct buffer *buf, bool client)
}

void
process_ip_header(struct context *c, unsigned int flags, struct buffer *buf)
process_ip_header(struct context *c, unsigned int flags, struct buffer *buf,
struct link_socket *sock)
{
if (!c->options.ce.mssfix)
{
Expand Down Expand Up @@ -1679,7 +1688,7 @@ process_ip_header(struct context *c, unsigned int flags, struct buffer *buf)
/* extract TOS from IP header */
if (flags & PIPV4_PASSTOS)
{
link_socket_extract_tos(c->c2.link_socket, &ipbuf);
link_socket_extract_tos(sock, &ipbuf);
}
#endif

Expand Down Expand Up @@ -1887,7 +1896,7 @@ process_outgoing_link(struct context *c, struct link_socket *sock)
*/

void
process_outgoing_tun(struct context *c)
process_outgoing_tun(struct context *c, struct link_socket *in_sock)
{
/*
* Set up for write() call to TUN/TAP
Expand All @@ -1904,9 +1913,8 @@ process_outgoing_tun(struct context *c)
* The --mssfix option requires
* us to examine the IP header (IPv4 or IPv6).
*/
process_ip_header(c,
PIP_MSSFIX | PIPV4_EXTRACT_DHCP_ROUTER | PIPV4_CLIENT_NAT | PIP_OUTGOING,
&c->c2.to_tun);
process_ip_header(c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIP_OUTGOING, &c->c2.to_tun,
in_sock);

if (c->c2.to_tun.len <= c->c2.frame.buf.payload_size)
{
Expand Down Expand Up @@ -2180,8 +2188,11 @@ io_wait_dowork(struct context *c, const unsigned int flags)
/*
* Configure event wait based on socket, tuntap flags.
*/
socket_set(c->c2.link_socket, c->c2.event_set, socket,
&c->c2.link_socket->ev_arg, NULL);
for (int i = 0; i < c->c1.link_sockets_num; i++)
{
socket_set(c->c2.link_sockets[i], c->c2.event_set, socket,
&c->c2.link_sockets[i]->ev_arg, NULL);
}
tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)tun_shift, NULL);
#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
if (socket & EVENT_READ && c->c2.did_open_tun)
Expand Down Expand Up @@ -2219,7 +2230,7 @@ io_wait_dowork(struct context *c, const unsigned int flags)

if (!c->sig->signal_received)
{
if (!(flags & IOW_CHECK_RESIDUAL) || !socket_read_residual(c->c2.link_socket))
if (!(flags & IOW_CHECK_RESIDUAL) || !sockets_read_residual(c))
{
int status;

Expand Down Expand Up @@ -2311,7 +2322,7 @@ process_io(struct context *c, struct link_socket *sock)
/* TUN device ready to accept write */
else if (status & TUN_WRITE)
{
process_outgoing_tun(c);
process_outgoing_tun(c, sock);
}
/* Incoming data on TCP/UDP port */
else if (status & SOCKET_READ)
Expand All @@ -2328,7 +2339,7 @@ process_io(struct context *c, struct link_socket *sock)
read_incoming_tun(c);
if (!IS_SIG(c))
{
process_incoming_tun(c);
process_incoming_tun(c, sock);
}
}
else if (status & DCO_READ)
Expand Down
24 changes: 14 additions & 10 deletions src/openvpn/forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,12 @@ void read_incoming_tun(struct context *c);
*
* If an error occurs, it is logged and the packet is dropped.
*
* @param c - The context structure of the VPN tunnel associated with the
* packet.
* @param c The context structure of the VPN tunnel associated with
* the packet.
* @param out_sock Socket that will be used to send out the packet.
*
*/
void process_incoming_tun(struct context *c);
void process_incoming_tun(struct context *c, struct link_socket *out_sock);


/**
Expand All @@ -246,10 +248,11 @@ void process_incoming_tun(struct context *c);
*
* If an error occurs, it is logged and the packet is dropped.
*
* @param c - The context structure of the VPN tunnel associated with
* the packet.
* @param c The context structure of the VPN tunnel associated
* with the packet.
* @param in_sock Socket where the packet was received.
*/
void process_outgoing_tun(struct context *c);
void process_outgoing_tun(struct context *c, struct link_socket *in_sock);


/**************************************************************************/
Expand Down Expand Up @@ -304,20 +307,21 @@ void reschedule_multi_process(struct context *c);
#define PIPV6_ICMP_NOHOST_SERVER (1<<6)


void process_ip_header(struct context *c, unsigned int flags, struct buffer *buf);
void process_ip_header(struct context *c, unsigned int flags, struct buffer *buf,
struct link_socket *sock);

bool schedule_exit(struct context *c);

static inline struct link_socket_info *
get_link_socket_info(struct context *c)
{
if (c->c2.link_socket_info)
if (c->c2.link_socket_infos)
{
return c->c2.link_socket_info;
return c->c2.link_socket_infos[0];
}
else
{
return &c->c2.link_socket->info;
return &c->c2.link_sockets[0]->info;
}
}

Expand Down
Loading

0 comments on commit 94b391d

Please sign in to comment.