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>
| ... | ... |
@@ -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); |