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>
This commit is contained in:
parent
61fa05c7c0
commit
faff133629
1 changed files with 19 additions and 9 deletions
28
dhcpv6.c
28
dhcpv6.c
|
@ -299,6 +299,7 @@ static struct opt_hdr *dhcpv6_ia_notonlink(struct opt_hdr *o, size_t len,
|
||||||
struct in6_addr *addr)
|
struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct opt_hdr *ia, *ia_addr;
|
struct opt_hdr *ia, *ia_addr;
|
||||||
|
char buf[INET6_ADDRSTRLEN];
|
||||||
struct in6_addr *req_addr;
|
struct in6_addr *req_addr;
|
||||||
size_t __len;
|
size_t __len;
|
||||||
int ia_type;
|
int ia_type;
|
||||||
|
@ -309,7 +310,7 @@ ia_ta:
|
||||||
ia = o;
|
ia = o;
|
||||||
|
|
||||||
while ((ia = dhcpv6_opt(ia, ia_type, &__len))) {
|
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)
|
if (ia_len > __len)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -328,8 +329,13 @@ ia_ta:
|
||||||
struct opt_ia_addr *next;
|
struct opt_ia_addr *next;
|
||||||
|
|
||||||
req_addr = (struct in6_addr *)(ia_addr + 1);
|
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;
|
return ia;
|
||||||
|
}
|
||||||
|
|
||||||
next = (struct opt_ia_addr *)ia_addr + 1;
|
next = (struct opt_ia_addr *)ia_addr + 1;
|
||||||
ia_addr = (struct opt_hdr *)next;
|
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),
|
if ((bad_ia = dhcpv6_ia_notonlink((struct opt_hdr *)(mh + 1),
|
||||||
mlen, &c->addr6))) {
|
mlen, &c->addr6))) {
|
||||||
n = OPT_IA_NA ? sizeof(struct opt_ia_na) :
|
info("DHCPv6: received CONFIRM with inappropriate IA,"
|
||||||
sizeof(struct opt_ia_ta);
|
" sending NotOnLink status in REPLY");
|
||||||
memcpy(&resp_not_on_link.var, bad_ia, n);
|
|
||||||
|
|
||||||
memcpy(&resp_not_on_link.var + n, &sc_not_on_link,
|
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,
|
||||||
sizeof(sc_not_on_link));
|
sizeof(sc_not_on_link));
|
||||||
n += sizeof(sc_not_on_link);
|
n += sizeof(sc_not_on_link);
|
||||||
|
|
||||||
memcpy(&resp_not_on_link.var + n, client_id,
|
memcpy(resp_not_on_link.var + n, client_id,
|
||||||
sizeof(struct opt_hdr) + client_id->l);
|
sizeof(struct opt_hdr) + ntohs(client_id->l));
|
||||||
n += sizeof(struct opt_hdr) + client_id->l;
|
n += sizeof(struct opt_hdr) + ntohs(client_id->l);
|
||||||
|
|
||||||
n = offsetof(struct resp_not_on_link_t, var) + n;
|
n = offsetof(struct resp_not_on_link_t, var) + n;
|
||||||
resp_not_on_link.uh.len = htons(n);
|
resp_not_on_link.uh.len = htons(n);
|
||||||
|
|
Loading…
Reference in a new issue