Browse code

Move dco_installed from sock->info to sock->info.lsa.actual

For tcp this makes no difference as the remote address of the
socket never changes. For udp this allows OpenVPN to differentiate
if a reconnecting client is using the same address as before or
from a different one. This allow sending via the normal userspace
socket in that case.

Patch v2: fix windows code path
Patch v3: fix mtcp server code path

Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: Antonio Quartulli <a@unstable.cc>
Message-Id: <20221124162642.3173118-1-arne@rfc2549.org>
URL: https://www.mail-archive.com/search?l=mid&q=20221124162642.3173118-1-arne@rfc2549.org
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Arne Schwabe authored on 2022/11/25 01:26:42
Showing 7 changed files
... ...
@@ -426,6 +426,22 @@ dco_check_pull_options(int msglevel, const struct options *o)
426 426
     return true;
427 427
 }
428 428
 
429
+static void
430
+addr_set_dco_installed(struct context *c)
431
+{
432
+    /* We ensure that all addresses we currently hold have the dco_installed
433
+     * bit set */
434
+    for (int i = 0; i < KEY_SCAN_SIZE; ++i)
435
+    {
436
+        struct key_state *ks = get_key_scan(c->c2.tls_multi, i);
437
+        if (ks)
438
+        {
439
+            ks->remote_addr.dco_installed = true;
440
+        }
441
+    }
442
+    get_link_socket_info(c)->lsa->actual.dco_installed = true;
443
+}
444
+
429 445
 int
430 446
 dco_p2p_add_new_peer(struct context *c)
431 447
 {
... ...
@@ -438,6 +454,8 @@ dco_p2p_add_new_peer(struct context *c)
438 438
 
439 439
     ASSERT(ls->info.connection_established);
440 440
 
441
+    addr_set_dco_installed(c);
442
+
441 443
     struct sockaddr *remoteaddr = &ls->info.lsa->actual.dest.addr.sa;
442 444
     struct tls_multi *multi = c->c2.tls_multi;
443 445
     int ret = dco_new_peer(&c->c1.tuntap->dco, multi->peer_id,
... ...
@@ -448,7 +466,7 @@ dco_p2p_add_new_peer(struct context *c)
448 448
     }
449 449
 
450 450
     c->c2.tls_multi->dco_peer_added = true;
451
-    c->c2.link_socket->info.dco_installed = true;
451
+    c->c2.link_socket->info.lsa->actual.dco_installed = true;
452 452
 
453 453
     return 0;
454 454
 }
... ...
@@ -522,11 +540,12 @@ dco_multi_add_new_peer(struct multi_context *m, struct multi_instance *mi)
522 522
 {
523 523
     struct context *c = &mi->context;
524 524
 
525
-    int peer_id = mi->context.c2.tls_multi->peer_id;
525
+    int peer_id = c->c2.tls_multi->peer_id;
526 526
     struct sockaddr *remoteaddr, *localaddr = NULL;
527 527
     struct sockaddr_storage local = { 0 };
528 528
     int sd = c->c2.link_socket->sd;
529 529
 
530
+
530 531
     if (c->mode == CM_CHILD_TCP)
531 532
     {
532 533
         /* the remote address will be inferred from the TCP socket endpoint */
... ...
@@ -537,9 +556,9 @@ dco_multi_add_new_peer(struct multi_context *m, struct multi_instance *mi)
537 537
         ASSERT(c->c2.link_socket_info->connection_established);
538 538
         remoteaddr = &c->c2.link_socket_info->lsa->actual.dest.addr.sa;
539 539
     }
540
+    addr_set_dco_installed(c);
540 541
 
541 542
     /* In server mode we need to fetch the remote addresses from the push config */
542
-
543 543
     struct in_addr vpn_ip4 = { 0 };
544 544
     struct in_addr *vpn_addr4 = NULL;
545 545
     if (c->c2.push_ifconfig_defined)
... ...
@@ -575,7 +594,7 @@ dco_multi_add_new_peer(struct multi_context *m, struct multi_instance *mi)
575 575
         {
576 576
             msg(D_DCO|M_ERRNO, "error closing TCP socket after DCO handover");
577 577
         }
578
-        c->c2.link_socket->info.dco_installed = true;
578
+        c->c2.link_socket->info.lsa->actual.dco_installed = true;
579 579
         c->c2.link_socket->sd = SOCKET_UNDEFINED;
580 580
     }
581 581
 
... ...
@@ -285,7 +285,7 @@ ovpn_nl_cb_finish(struct nl_msg (*msg) __attribute__ ((unused)), void *arg)
285 285
  *
286 286
  * We pass the error code to the user by means of a variable pointed by *arg
287 287
  * (supplied by the user when setting this callback) and we parse the kernel
288
- * reply to see if it contains a human readable error. If found, it is printed.
288
+ * reply to see if it contains a human-readable error. If found, it is printed.
289 289
  */
290 290
 static int
291 291
 ovpn_nl_cb_error(struct sockaddr_nl (*nla) __attribute__ ((unused)),
... ...
@@ -1643,13 +1643,13 @@ process_ip_header(struct context *c, unsigned int flags, struct buffer *buf)
1643 1643
  * standard Overlapped I/O.
1644 1644
  *
1645 1645
  * Hide that complexity (...especially if more platforms show up
1646
- * in future...) in a small inline function.
1646
+ * in the future...) in a small inline function.
1647 1647
  */
1648 1648
 static inline bool
1649
-should_use_dco_socket(struct link_socket *sock)
1649
+should_use_dco_socket(struct link_socket_actual *actual)
1650 1650
 {
1651 1651
 #if defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
1652
-    return sock->info.dco_installed;
1652
+    return actual->dco_installed;
1653 1653
 #else
1654 1654
     return false;
1655 1655
 #endif
... ...
@@ -1728,7 +1728,7 @@ process_outgoing_link(struct context *c)
1728 1728
                 socks_preprocess_outgoing_link(c, &to_addr, &size_delta);
1729 1729
 
1730 1730
                 /* Send packet */
1731
-                if (should_use_dco_socket(c->c2.link_socket))
1731
+                if (should_use_dco_socket(c->c2.to_link_addr))
1732 1732
                 {
1733 1733
                     size = dco_do_write(&c->c1.tuntap->dco,
1734 1734
                                         c->c2.tls_multi->peer_id,
... ...
@@ -3678,7 +3678,7 @@ do_close_link_socket(struct context *c)
3678 3678
      * closed in do_close_tun(). Set it to UNDEFINED so
3679 3679
      * we won't use WinSock API to close it. */
3680 3680
     if (tuntap_is_dco_win(c->c1.tuntap) && c->c2.link_socket
3681
-        && c->c2.link_socket->info.dco_installed)
3681
+        && c->c2.link_socket->info.lsa->actual.dco_installed)
3682 3682
     {
3683 3683
         c->c2.link_socket->sd = SOCKET_UNDEFINED;
3684 3684
     }
... ...
@@ -402,7 +402,7 @@ multi_tcp_wait_lite(struct multi_context *m, struct multi_instance *mi, const in
402 402
 
403 403
     tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */
404 404
 
405
-    if (mi && mi->context.c2.link_socket->info.dco_installed)
405
+    if (mi && mi->context.c2.link_socket->info.lsa->actual.dco_installed)
406 406
     {
407 407
         /* If we got a socket that has been handed over to the kernel
408 408
          * we must not call the normal socket function to figure out
... ...
@@ -537,7 +537,7 @@ multi_tcp_dispatch(struct multi_context *m, struct multi_instance *mi, const int
537 537
 
538 538
         case TA_INITIAL:
539 539
             ASSERT(mi);
540
-            if (!mi->context.c2.link_socket->info.dco_installed)
540
+            if (!mi->context.c2.link_socket->info.lsa->actual.dco_installed)
541 541
             {
542 542
                 multi_tcp_set_global_rw_flags(m, mi);
543 543
             }
... ...
@@ -590,7 +590,7 @@ multi_tcp_post(struct multi_context *m, struct multi_instance *mi, const int act
590 590
             }
591 591
             else
592 592
             {
593
-                if (!c->c2.link_socket->info.dco_installed)
593
+                if (!c->c2.link_socket->info.lsa->actual.dco_installed)
594 594
                 {
595 595
                     multi_tcp_set_global_rw_flags(m, mi);
596 596
                 }
... ...
@@ -2147,7 +2147,7 @@ create_socket_dco_win(struct context *c, struct link_socket *sock,
2147 2147
                       get_server_poll_remaining_time(sock->server_poll_timeout),
2148 2148
                       signal_received);
2149 2149
 
2150
-    sock->info.dco_installed = true;
2150
+    sock->info.lsa->actual.dco_installed = true;
2151 2151
 
2152 2152
     if (*signal_received)
2153 2153
     {
... ...
@@ -3480,7 +3480,7 @@ link_socket_write_udp_posix_sendmsg(struct link_socket *sock,
3480 3480
 static int
3481 3481
 socket_get_last_error(const struct link_socket *sock)
3482 3482
 {
3483
-    if (sock->info.dco_installed)
3483
+    if (sock->info.lsa->actual.dco_installed)
3484 3484
     {
3485 3485
         return GetLastError();
3486 3486
     }
... ...
@@ -3521,7 +3521,7 @@ socket_recv_queue(struct link_socket *sock, int maxsize)
3521 3521
         ASSERT(ResetEvent(sock->reads.overlapped.hEvent));
3522 3522
         sock->reads.flags = 0;
3523 3523
 
3524
-        if (sock->info.dco_installed)
3524
+        if (sock->info.lsa->actual.dco_installed)
3525 3525
         {
3526 3526
             status = ReadFile((HANDLE)sock->sd, wsabuf[0].buf, wsabuf[0].len,
3527 3527
                               &sock->reads.size, &sock->reads.overlapped);
... ...
@@ -3626,7 +3626,7 @@ socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct lin
3626 3626
         ASSERT(ResetEvent(sock->writes.overlapped.hEvent));
3627 3627
         sock->writes.flags = 0;
3628 3628
 
3629
-        if (sock->info.dco_installed)
3629
+        if (sock->info.lsa->actual.dco_installed)
3630 3630
         {
3631 3631
             status = WriteFile((HANDLE)sock->sd, wsabuf[0].buf, wsabuf[0].len,
3632 3632
                                &sock->writes.size, &sock->writes.overlapped);
... ...
@@ -88,6 +88,7 @@ struct link_socket_actual
88 88
     /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */
89 89
 
90 90
     struct openvpn_sockaddr dest;
91
+    bool dco_installed;
91 92
 #if ENABLE_IP_PKTINFO
92 93
     union {
93 94
 #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
... ...
@@ -121,7 +122,6 @@ struct link_socket_info
121 121
     sa_family_t af;                     /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/
122 122
     bool bind_ipv6_only;
123 123
     int mtu_changed;            /* Set to true when mtu value is changed */
124
-    bool dco_installed;
125 124
 };
126 125
 
127 126
 /*
... ...
@@ -1036,9 +1036,9 @@ link_socket_read_udp_win32(struct link_socket *sock,
1036 1036
                            struct link_socket_actual *from)
1037 1037
 {
1038 1038
     sockethandle_t sh = { .s = sock->sd };
1039
-    if (sock->info.dco_installed)
1039
+    if (sock->info.lsa->actual.dco_installed)
1040 1040
     {
1041
-        from->dest = sock->info.lsa->actual.dest;
1041
+        *from = sock->info.lsa->actual;
1042 1042
         sh.is_handle = true;
1043 1043
     }
1044 1044
     return sockethandle_finalize(sh, &sock->reads, buf, from);
... ...
@@ -1059,7 +1059,7 @@ link_socket_read(struct link_socket *sock,
1059 1059
                  struct link_socket_actual *from)
1060 1060
 {
1061 1061
     if (proto_is_udp(sock->info.proto)
1062
-        || sock->info.dco_installed)
1062
+        || sock->info.lsa->actual.dco_installed)
1063 1063
     /* unified UDPv4 and UDPv6, for DCO the kernel
1064 1064
      * will strip the length header */
1065 1065
     {
... ...
@@ -1102,7 +1102,7 @@ link_socket_write_win32(struct link_socket *sock,
1102 1102
 {
1103 1103
     int err = 0;
1104 1104
     int status = 0;
1105
-    sockethandle_t sh = { .s = sock->sd, .is_handle = sock->info.dco_installed };
1105
+    sockethandle_t sh = { .s = sock->sd, .is_handle = sock->info.lsa->actual.dco_installed };
1106 1106
     if (overlapped_io_active(&sock->writes))
1107 1107
     {
1108 1108
         status = sockethandle_finalize(sh, &sock->writes, NULL, NULL);
... ...
@@ -1176,7 +1176,7 @@ link_socket_write(struct link_socket *sock,
1176 1176
                   struct buffer *buf,
1177 1177
                   struct link_socket_actual *to)
1178 1178
 {
1179
-    if (proto_is_udp(sock->info.proto) || sock->info.dco_installed)
1179
+    if (proto_is_udp(sock->info.proto) || to->dco_installed)
1180 1180
     {
1181 1181
         /* unified UDPv4 and UDPv6 and DCO (kernel adds size header) */
1182 1182
         return link_socket_write_udp(sock, buf, to);