aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2021-10-20 11:10:23 +0200
committerStefano Brivio <sbrivio@redhat.com>2021-10-20 11:10:23 +0200
commit9618d247006a41fba5c1b0470e4723196f96b424 (patch)
tree915f636f855f4cae765ecb1eb6542a387282633f
parent12cfa6444cd239dbc04391027ad3161f53b6901c (diff)
downloadpasst-9618d247006a41fba5c1b0470e4723196f96b424.tar
passt-9618d247006a41fba5c1b0470e4723196f96b424.tar.gz
passt-9618d247006a41fba5c1b0470e4723196f96b424.tar.bz2
passt-9618d247006a41fba5c1b0470e4723196f96b424.tar.lz
passt-9618d247006a41fba5c1b0470e4723196f96b424.tar.xz
passt-9618d247006a41fba5c1b0470e4723196f96b424.tar.zst
passt-9618d247006a41fba5c1b0470e4723196f96b424.zip
ndp, dhcpv6, tcp, udp: Always use link-local as source if gateway isn't
This shouldn't happen on any sane configuration, but I just met an example of that: the default IPv6 gateway on the host is configured with a global unicast address, we use that as source for RA, DHCPv6 replies, and the guest ignores it. Same later on if we talk TCP or UDP and the guest has no idea where that address comes from. Use our link-local address in case the gateway address is global. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--dhcpv6.c10
-rw-r--r--ndp.c6
-rw-r--r--tcp.c12
-rw-r--r--udp.c5
4 files changed, 28 insertions, 5 deletions
diff --git a/dhcpv6.c b/dhcpv6.c
index cac220e..27d3a9c 100644
--- a/dhcpv6.c
+++ b/dhcpv6.c
@@ -452,6 +452,7 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len)
{
struct ipv6hdr *ip6h = (struct ipv6hdr *)(eh + 1);
struct opt_hdr *ia, *bad_ia, *client_id, *server_id;
+ struct in6_addr *src;
struct msg_hdr *mh;
struct udphdr *uh;
uint8_t proto;
@@ -476,6 +477,11 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len)
c->addr6_ll_seen = ip6h->saddr;
+ if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
+ src = &c->gw6;
+ else
+ src = &c->addr6_ll;
+
mh = (struct msg_hdr *)(uh + 1);
mlen -= sizeof(struct msg_hdr);
@@ -527,7 +533,7 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len)
resp_not_on_link.hdr.xid = mh->xid;
- tap_ip_send(c, &c->gw6, IPPROTO_UDP,
+ tap_ip_send(c, src, IPPROTO_UDP,
(char *)&resp_not_on_link, n, mh->xid);
return 1;
@@ -577,7 +583,7 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len)
resp.hdr.xid = mh->xid;
- tap_ip_send(c, &c->gw6, IPPROTO_UDP, (char *)&resp, n, mh->xid);
+ tap_ip_send(c, src, IPPROTO_UDP, (char *)&resp, n, mh->xid);
c->addr6_seen = c->addr6;
return 1;
diff --git a/ndp.c b/ndp.c
index 10c091c..e779ae0 100644
--- a/ndp.c
+++ b/ndp.c
@@ -183,7 +183,11 @@ int ndp(struct ctx *c, struct ethhdr *eh, size_t len)
c->addr6_seen = ip6h->saddr;
ip6hr->daddr = ip6h->saddr;
- ip6hr->saddr = c->gw6;
+ if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
+ ip6hr->saddr = c->gw6;
+ else
+ ip6hr->saddr = c->addr6_ll;
+
ip6hr->payload_len = htons(sizeof(*ihr) + len);
ip6hr->hop_limit = IPPROTO_ICMPV6;
ihr->icmp6_cksum = 0;
diff --git a/tcp.c b/tcp.c
index c8815c5..6b5d29b 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2921,8 +2921,16 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref,
if (IN6_IS_ADDR_LOOPBACK(&sa6.sin6_addr) ||
!memcmp(&sa6.sin6_addr, &c->addr6_seen, sizeof(c->gw6)) ||
- !memcmp(&sa6.sin6_addr, &c->addr6, sizeof(c->gw6)))
- memcpy(&sa6.sin6_addr, &c->gw6, sizeof(c->gw6));
+ !memcmp(&sa6.sin6_addr, &c->addr6, sizeof(c->gw6))) {
+ struct in6_addr *src;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
+ src = &c->gw6;
+ else
+ src = &c->addr6_ll;
+
+ memcpy(&sa6.sin6_addr, src, sizeof(*src));
+ }
memcpy(&conn->a.a6, &sa6.sin6_addr, sizeof(conn->a.a6));
diff --git a/udp.c b/udp.c
index bd03036..229c038 100644
--- a/udp.c
+++ b/udp.c
@@ -698,6 +698,11 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
in_port_t src = htons(b->s_in6.sin6_port);
b->ip6h.daddr = c->addr6_ll_seen;
+ if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
+ b->ip6h.saddr = c->gw6;
+ else
+ b->ip6h.saddr = c->addr6_ll;
+
b->ip6h.saddr = c->gw6;
udp_tap_map[V6][src].ts_local = now->tv_sec;