diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2021-04-21 17:15:23 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2021-04-21 17:15:23 +0200 |
commit | faff1336296741ab434ae33b948cffe57a51886d (patch) | |
tree | 30765570aca3fc4688ebc96c31f85740ebffc2e9 /dhcpv6.c | |
parent | 61fa05c7c0c566cef4e85103841afdbbe0b4f3f6 (diff) | |
download | passt-faff1336296741ab434ae33b948cffe57a51886d.tar passt-faff1336296741ab434ae33b948cffe57a51886d.tar.gz passt-faff1336296741ab434ae33b948cffe57a51886d.tar.bz2 passt-faff1336296741ab434ae33b948cffe57a51886d.tar.lz passt-faff1336296741ab434ae33b948cffe57a51886d.tar.xz passt-faff1336296741ab434ae33b948cffe57a51886d.tar.zst passt-faff1336296741ab434ae33b948cffe57a51886d.zip |
dhcpv6: Fix REPLY messages with NotOnLink status code
The NotOnLink status code needs to be appended to the existing IA
content, because if we omit the requested addresses in the reply,
ISC's dhclient handles it as a NoAddrsAvail response.
Also fix length accounting (we would send a bunch of zeroes after
the IA otherwise), and print an informational message with the
requested address, if it's not appropriate for the link.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'dhcpv6.c')
-rw-r--r-- | dhcpv6.c | 28 |
1 files changed, 19 insertions, 9 deletions
@@ -299,6 +299,7 @@ static struct opt_hdr *dhcpv6_ia_notonlink(struct opt_hdr *o, size_t len, struct in6_addr *addr) { struct opt_hdr *ia, *ia_addr; + char buf[INET6_ADDRSTRLEN]; struct in6_addr *req_addr; size_t __len; int ia_type; @@ -309,7 +310,7 @@ ia_ta: ia = o; while ((ia = dhcpv6_opt(ia, ia_type, &__len))) { - size_t ia_len = ntohs(ia->l) - sizeof(struct opt_hdr); + size_t ia_len = ntohs(ia->l); if (ia_len > __len) return NULL; @@ -328,8 +329,13 @@ ia_ta: struct opt_ia_addr *next; req_addr = (struct in6_addr *)(ia_addr + 1); - if (memcmp(addr, req_addr, sizeof(*addr))) + + if (memcmp(addr, req_addr, sizeof(*addr))) { + info("DHCPv6: requested address %s not on link", + inet_ntop(AF_INET6, req_addr, + buf, sizeof(buf))); return ia; + } next = (struct opt_ia_addr *)ia_addr + 1; ia_addr = (struct opt_hdr *)next; @@ -412,17 +418,21 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len) if ((bad_ia = dhcpv6_ia_notonlink((struct opt_hdr *)(mh + 1), mlen, &c->addr6))) { - n = OPT_IA_NA ? sizeof(struct opt_ia_na) : - sizeof(struct opt_ia_ta); - memcpy(&resp_not_on_link.var, bad_ia, n); + info("DHCPv6: received CONFIRM with inappropriate IA," + " sending NotOnLink status in REPLY"); + + n = ntohs(bad_ia->l) + sizeof(struct opt_hdr); + bad_ia->l = htons(n - sizeof(struct opt_hdr) + + sizeof(sc_not_on_link)); + memcpy(resp_not_on_link.var, bad_ia, n); - memcpy(&resp_not_on_link.var + n, &sc_not_on_link, + memcpy(resp_not_on_link.var + n, &sc_not_on_link, sizeof(sc_not_on_link)); n += sizeof(sc_not_on_link); - memcpy(&resp_not_on_link.var + n, client_id, - sizeof(struct opt_hdr) + client_id->l); - n += sizeof(struct opt_hdr) + client_id->l; + memcpy(resp_not_on_link.var + n, client_id, + sizeof(struct opt_hdr) + ntohs(client_id->l)); + n += sizeof(struct opt_hdr) + ntohs(client_id->l); n = offsetof(struct resp_not_on_link_t, var) + n; resp_not_on_link.uh.len = htons(n); |