Skip to content

Commit

Permalink
dco: fix source IP selection
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
LGA1150 committed Feb 1, 2025
1 parent bfa5f0b commit 83e8806
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/openvpn/dco.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ dco_p2p_add_new_peer(struct context *c)
ASSERT(sock->info.connection_established);

struct sockaddr *remoteaddr = &sock->info.lsa->actual.dest.addr.sa;
struct sockaddr *localaddr = NULL;
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 @@ -503,8 +504,12 @@ dco_p2p_add_new_peer(struct context *c)
c->c2.tls_multi->dco_peer_id = -1;
}
#endif
if (sock->bind_local && sock->info.lsa->bind_local) {
localaddr = sock->info.lsa->bind_local->ai_addr;
}

int ret = dco_new_peer(&c->c1.tuntap->dco, multi->peer_id,
c->c2.link_sockets[0]->sd, NULL, remoteaddr, NULL, NULL);
c->c2.link_sockets[0]->sd, localaddr, remoteaddr, NULL, NULL);
if (ret < 0)
{
return ret;
Expand Down Expand Up @@ -550,7 +555,7 @@ dco_multi_get_localaddr(struct multi_context *m, struct multi_instance *mi,
{
struct sockaddr_in *sock_in4 = (struct sockaddr_in *)local;
#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
sock_in4->sin_addr = actual->pi.in4.ipi_addr;
sock_in4->sin_addr = actual->pi.in4.ipi_spec_dst;
#elif defined(IP_RECVDSTADDR)
sock_in4->sin_addr = actual->pi.in4;
#else
Expand Down Expand Up @@ -616,10 +621,15 @@ dco_multi_add_new_peer(struct multi_context *m, struct multi_instance *mi)
vpn_addr6 = &c->c2.push_ifconfig_ipv6_local;
}

struct link_socket *ls = c->c2.link_sockets[0];
if (dco_multi_get_localaddr(m, mi, &local))
{
localaddr = (struct sockaddr *)&local;
}
else if (ls->bind_local && ls->info.lsa->bind_local)
{
localaddr = ls->info.lsa->bind_local->ai_addr;
}

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

0 comments on commit 83e8806

Please sign in to comment.