diff options
-rw-r--r-- | dhcpv6.c | 10 | ||||
-rw-r--r-- | ndp.c | 6 | ||||
-rw-r--r-- | tcp.c | 12 | ||||
-rw-r--r-- | udp.c | 5 |
4 files changed, 28 insertions, 5 deletions
@@ -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; @@ -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; @@ -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)); @@ -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; |