aboutgitcodebugslistschat
path: root/ndp.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2021-05-21 11:14:47 +0200
committerStefano Brivio <sbrivio@redhat.com>2021-05-21 11:14:47 +0200
commit9010054ea4ceee9105aa938f15b79a3a91ec5969 (patch)
treef9f1ca6a2b506d6b4b2f1fdb210e702d016fecf8 /ndp.c
parent0231ac1c86578a8dac2ae6531d30c71ba89688e1 (diff)
downloadpasst-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.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/ndp.c b/ndp.c
index 1e0d817..40cfe93 100644
--- a/ndp.c
+++ b/ndp.c
@@ -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 */