From 9010054ea4ceee9105aa938f15b79a3a91ec5969 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 21 May 2021 11:14:47 +0200 Subject: dhcp, ndp, dhcpv6: Support for multiple DNS servers, search list Add support for a variable amount of DNS servers, including zero, from /etc/resolv.conf, in DHCP, NDP and DHCPv6 implementations. Introduce support for domain search list for DHCP (RFC 3397), NDP (RFC 8106), and DHCPv6 (RFC 3646), also sourced from /etc/resolv.conf. Signed-off-by: Stefano Brivio --- ndp.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'ndp.c') diff --git a/ndp.c b/ndp.c index 1e0d817..40cfe93 100644 --- a/ndp.c +++ b/ndp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include #include #include -#include #include "passt.h" #include "util.h" @@ -76,6 +76,9 @@ int ndp(struct ctx *c, struct ethhdr *eh, size_t len) memcpy(p, c->mac, ETH_ALEN); p += 6; } else if (ih->icmp6_type == RS) { + size_t len = 0; + int i, n; + info("NDP: received RS, sending RA"); ihr->icmp6_type = RA; ihr->icmp6_code = 0; @@ -95,13 +98,48 @@ int ndp(struct ctx *c, struct ethhdr *eh, size_t len) memcpy(p, &c->addr6, 8); /* prefix */ p += 16; - *p++ = 25; /* RDNS */ - *p++ = 3; /* length */ - p += 2; - *(uint32_t *)p = htonl(60); /* lifetime */ - p += 4; - memcpy(p, &c->dns6, 16); /* address */ - p += 16; + for (n = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->dns6[n]); n++); + if (n) { + *p++ = 25; /* RDNSS */ + *p++ = 1 + 2 * n; /* length */ + p += 2; /* reserved */ + *(uint32_t *)p = htonl(60); /* lifetime */ + p += 4; + + for (i = 0; i < n; i++) { + memcpy(p, &c->dns6[i], 16); /* address */ + p += 16; + } + } + + for (n = 0; *c->dns_search[n].n; n++) + len += strlen(c->dns_search[n].n) + 2; + if (len) { + *p++ = 31; /* DNSSL */ + *p++ = 2 + (len + 8 - 1) / 8; /* length */ + p += 2; /* reserved */ + *(uint32_t *)p = htonl(60); /* lifetime */ + p += 4; + + for (i = 0; i < n; i++) { + char *dot; + + *(p++) = '.'; + + strncpy((char *)p, c->dns_search[i].n, + sizeof(buf) - + ((intptr_t)p - (intptr_t)buf)); + for (dot = (char *)p - 1; *dot; dot++) { + if (*dot == '.') + *dot = strcspn(dot + 1, "."); + } + p += strlen(c->dns_search[i].n); + *(p++) = 0; + } + + memset(p, 0, len % 8); /* padding */ + p += len % 8; + } *p++ = 1; /* source ll */ *p++ = 1; /* length */ -- cgit v1.2.3