[M] Change in openvpn[master]: socket: adopt a pre-created UDP socket for a client connection

"stipa \(Code Review\) via Openvpn-devel" <[email protected]>
Newsgroups gmane.network.openvpn.devel
Message-ID <[email protected]>
Attention is currently required from: plaisthos.

Hello plaisthos,

I'd like you to do a code review.
Please visit

    http://gerrit.openvpn.net/c/openvpn/+/1769?usp=email

to review the following change.


Change subject: socket: adopt a pre-created UDP socket for a client connection
......................................................................

socket: adopt a pre-created UDP socket for a client connection

Add LS_MODE_UDP_ADOPT: a client link_socket can take ownership of an
already-bound UDP socket handed off via c2.oob_probe_adopt/oob_probe_sd
instead of creating its own, and pins c2.oob_probe_remote as the outgoing
address. This lets the OOB server-probe socket become the connection socket,
so the source IP+port and destination match what the server's handshake
cookie is bound to.

  - link_socket_init_phase1: adopt the fd, inherit the address family, skip the
    local bind, and pre-set lsa->actual (resolve_remote preserves an already-
    defined actual)
  - link_socket_init_phase2: skip create_socket() so the adopted fd is not
    clobbered (overlapped-I/O init is fd-independent, so Windows is fine)
  - do_init_socket_phase1: select the mode for the single client socket

Dormant until the client sets oob_probe_adopt (next commit).

Change-Id: Iec384ee6844ab278b280d6eafec8aaecf9dde755
Signed-off-by: Lev Stipakov <[email protected]>
---
M src/openvpn/init.c
M src/openvpn/openvpn.h
M src/openvpn/socket.c
M src/openvpn/socket.h
4 files changed, 65 insertions(+), 2 deletions(-)



  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/69/1769/1

diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index e0d6a14..8eca6f7 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -3820,6 +3820,12 @@
                 mode = LS_MODE_TCP_ACCEPT_FROM;
             }
         }
+        /* adopt the OOB server-probe socket as this client's connection socket
+         * (handshake shortcut); only the single client socket is ever adopted */
+        else if (c->c2.oob_probe_adopt && i == 0)
+        {
+            mode = LS_MODE_UDP_ADOPT;
+        }
 
         /* init each socket with its specific args */
         link_socket_init_phase1(c, i, mode);
@@ -3985,6 +3991,16 @@
 static void
 do_close_link_socket(struct context *c)
 {
+    /* An OOB probe socket handed off for the handshake shortcut is adopted by the
+     * link socket in link_socket_init_phase1() (which clears oob_probe_sd). If the
+     * connection attempt aborted before that, the fd is still owned here; close it
+     * so it is not leaked when context_clear_2() zeroes c2. */
+    if (c->c2.oob_probe_sd != SOCKET_UNDEFINED)
+    {
+        openvpn_close_socket(c->c2.oob_probe_sd);
+        c->c2.oob_probe_sd = SOCKET_UNDEFINED;
+    }
+
     if (c->c2.link_sockets && c->c2.link_socket_owned)
     {
         for (int i = 0; i < c->c1.link_sockets_num; i++)
diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
index fa00822..e5a1d76 100644
--- a/src/openvpn/openvpn.h
+++ b/src/openvpn/openvpn.h
@@ -239,7 +239,16 @@
 
     bool link_socket_owned;
 
-    const struct link_socket *accept_from;   /* possibly do accept() on a parent link_socket */
+    const struct link_socket *accept_from; /* possibly do accept() on a parent link_socket */
+
+    /* OOB server-probe handshake shortcut: when oob_probe_adopt is true, the
+     * connection adopts oob_probe_sd (the winning remote's already-bound probe
+     * socket) instead of creating one, and pins oob_probe_remote (the exact
+     * address probed) as the outgoing address, so the source IP+port and the
+     * destination match what the server's handshake cookie is bound to. */
+    bool oob_probe_adopt;
+    socket_descriptor_t oob_probe_sd;
+    struct openvpn_sockaddr oob_probe_remote;
 
     struct link_socket_actual *to_link_addr; /* IP address of remote */
     struct link_socket_actual from;          /* address of incoming datagram */
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index df2cc9e..a9dca0a 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -1428,6 +1428,41 @@
         /* inherit (possibly guessed) info AF from parent context */
         sock->info.af = c->c2.accept_from->info.af;
     }
+    else if (mode == LS_MODE_UDP_ADOPT)
+    {
+        /* Adopt the OOB probe socket: same source IP+port the server's cookie is
+         * bound to. It is already bound, so do not bind again. */
+        ASSERT(c->c2.oob_probe_sd != SOCKET_UNDEFINED);
+        sock->sd = c->c2.oob_probe_sd;
+        c->c2.oob_probe_sd = SOCKET_UNDEFINED; /* ownership moves to the link socket */
+        sock->info.af = c->c2.oob_probe_remote.addr.sa.sa_family;
+        sock->bind_local = false;
+
+        /* The probe socket was created plainly, so apply the same options
+         * create_socket() would (it is already bound, so no bind here).
+         * --multihome's IP_PKTINFO never applies to a probing client, so it is
+         * intentionally not set. */
+        sock->sockflags |= SF_GETADDRINFO_DGRAM;
+        socket_set_buffers(sock->sd, &sock->socket_buffer_sizes, true);
+        socket_set_mark(sock->sd, sock->mark);
+#if defined(TARGET_LINUX)
+        if (sock->bind_dev)
+        {
+            msg(M_INFO, "Using bind-dev %s", sock->bind_dev);
+            if (setsockopt(sock->sd, SOL_SOCKET, SO_BINDTODEVICE, sock->bind_dev,
+                           strlen(sock->bind_dev) + 1)
+                != 0)
+            {
+                msg(M_WARN | M_ERRNO, "WARN: setsockopt SO_BINDTODEVICE=%s failed", sock->bind_dev);
+            }
+        }
+#endif
+
+        /* Pin the exact address we probed so the connection targets the address
+         * the cookie was minted for; resolve_remote() preserves a defined actual. */
+        CLEAR(sock->info.lsa->actual);
+        sock->info.lsa->actual.dest = c->c2.oob_probe_remote;
+    }
 
     /* are we running in HTTP proxy mode? */
     if (sock->http_proxy)
@@ -1720,7 +1755,7 @@
         goto done;
     }
 #endif
-    if (sock->info.lsa->current_remote)
+    if (sock->mode != LS_MODE_UDP_ADOPT && sock->info.lsa->current_remote)
     {
         create_socket(sock, sock->info.lsa->current_remote);
     }
diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h
index cd4e8ed..d807f36 100644
--- a/src/openvpn/socket.h
+++ b/src/openvpn/socket.h
@@ -197,6 +197,9 @@
 #define LS_MODE_DEFAULT         0
 #define LS_MODE_TCP_LISTEN      1
 #define LS_MODE_TCP_ACCEPT_FROM 2
+/* Adopt a pre-created, already-bound UDP socket (from the OOB server probe) as
+ * the connection socket, instead of creating one. */
+#define LS_MODE_UDP_ADOPT       3
     int mode;
 
     int resolve_retry_seconds;

-- 
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1769?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: Iec384ee6844ab278b280d6eafec8aaecf9dde755
Gerrit-Change-Number: 1769
Gerrit-PatchSet: 1
Gerrit-Owner: stipa <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>

_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.