Skip to content

Commit 83e8806

Browse files
committed
dco: fix source IP selection
When multihome option is enabled, OpenVPN passes ipi_addr to DCO, which is always 0.0.0.0. It should use ipi_spec_dst instead. When local option is present, OpenVPN does not pass it to DCO. As a result, Linux may pick a different IP as the source IP, breaking the connection. Signed-off-by: Qingfang Deng <[email protected]>
1 parent bfa5f0b commit 83e8806

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

src/openvpn/dco.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ dco_p2p_add_new_peer(struct context *c)
493493
ASSERT(sock->info.connection_established);
494494

495495
struct sockaddr *remoteaddr = &sock->info.lsa->actual.dest.addr.sa;
496+
struct sockaddr *localaddr = NULL;
496497
struct tls_multi *multi = c->c2.tls_multi;
497498
#ifdef TARGET_FREEBSD
498499
/* In Linux in P2P mode the kernel automatically removes an existing peer
@@ -503,8 +504,12 @@ dco_p2p_add_new_peer(struct context *c)
503504
c->c2.tls_multi->dco_peer_id = -1;
504505
}
505506
#endif
507+
if (sock->bind_local && sock->info.lsa->bind_local) {
508+
localaddr = sock->info.lsa->bind_local->ai_addr;
509+
}
510+
506511
int ret = dco_new_peer(&c->c1.tuntap->dco, multi->peer_id,
507-
c->c2.link_sockets[0]->sd, NULL, remoteaddr, NULL, NULL);
512+
c->c2.link_sockets[0]->sd, localaddr, remoteaddr, NULL, NULL);
508513
if (ret < 0)
509514
{
510515
return ret;
@@ -550,7 +555,7 @@ dco_multi_get_localaddr(struct multi_context *m, struct multi_instance *mi,
550555
{
551556
struct sockaddr_in *sock_in4 = (struct sockaddr_in *)local;
552557
#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
553-
sock_in4->sin_addr = actual->pi.in4.ipi_addr;
558+
sock_in4->sin_addr = actual->pi.in4.ipi_spec_dst;
554559
#elif defined(IP_RECVDSTADDR)
555560
sock_in4->sin_addr = actual->pi.in4;
556561
#else
@@ -616,10 +621,15 @@ dco_multi_add_new_peer(struct multi_context *m, struct multi_instance *mi)
616621
vpn_addr6 = &c->c2.push_ifconfig_ipv6_local;
617622
}
618623

624+
struct link_socket *ls = c->c2.link_sockets[0];
619625
if (dco_multi_get_localaddr(m, mi, &local))
620626
{
621627
localaddr = (struct sockaddr *)&local;
622628
}
629+
else if (ls->bind_local && ls->info.lsa->bind_local)
630+
{
631+
localaddr = ls->info.lsa->bind_local->ai_addr;
632+
}
623633

624634
int ret = dco_new_peer(&c->c1.tuntap->dco, peer_id, sd, localaddr,
625635
remoteaddr, vpn_addr4, vpn_addr6);

0 commit comments

Comments
 (0)