diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2021-05-21 11:14:47 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2021-05-21 11:14:47 +0200 |
commit | 9010054ea4ceee9105aa938f15b79a3a91ec5969 (patch) | |
tree | f9f1ca6a2b506d6b4b2f1fdb210e702d016fecf8 /ndp.c | |
parent | 0231ac1c86578a8dac2ae6531d30c71ba89688e1 (diff) | |
download | passt-9010054ea4ceee9105aa938f15b79a3a91ec5969.tar passt-9010054ea4ceee9105aa938f15b79a3a91ec5969.tar.gz passt-9010054ea4ceee9105aa938f15b79a3a91ec5969.tar.bz2 passt-9010054ea4ceee9105aa938f15b79a3a91ec5969.tar.lz passt-9010054ea4ceee9105aa938f15b79a3a91ec5969.tar.xz passt-9010054ea4ceee9105aa938f15b79a3a91ec5969.tar.zst passt-9010054ea4ceee9105aa938f15b79a3a91ec5969.zip |
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 <sbrivio@redhat.com>
Diffstat (limited to 'ndp.c')
-rw-r--r-- | ndp.c | 54 |
1 files changed, 46 insertions, 8 deletions
@@ -14,6 +14,7 @@ #include <stdint.h> #include <unistd.h> #include <string.h> +#include <arpa/inet.h> #include <linux/if_ether.h> #include <linux/ip.h> #include <linux/ipv6.h> @@ -21,7 +22,6 @@ #include <linux/udp.h> #include <net/if.h> #include <net/if_arp.h> -#include <arpa/inet.h> #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 */ |