From e06cde91678527199814b2bb7d25b3b278cb5beb Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Wed, 4 May 2016 12:16:45 +0200 Subject: [PATCH] uradvd: add --rdnss option This option may be specified multiple times (up to 3). --- net/uradvd/src/uradvd.c | 51 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/net/uradvd/src/uradvd.c b/net/uradvd/src/uradvd.c index 03d9dca..2b64caf 100644 --- a/net/uradvd/src/uradvd.c +++ b/net/uradvd/src/uradvd.c @@ -59,12 +59,14 @@ #define MAX_PREFIXES 8 +#define MAX_RDNSS 3 /* These are in seconds */ #define AdvValidLifetime 86400u #define AdvPreferredLifetime 14400u #define AdvDefaultLifetime 0u #define AdvCurHopLimit 64u +#define AdvRDNSSLifetime 1200u #define MinRtrAdvInterval 200u #define MaxRtrAdvInterval 600u @@ -88,6 +90,13 @@ struct iface { uint8_t mac[6]; }; +struct __attribute__((__packed__)) nd_opt_rdnss { + uint8_t nd_opt_rdnss_type; + uint8_t nd_opt_rdnss_len; + uint16_t nd_opt_rdnss_reserved; + uint32_t nd_opt_rdnss_lifetime; +}; + static struct global { struct iface iface; @@ -105,6 +114,9 @@ static struct global { size_t n_prefixes; struct in6_addr prefixes[MAX_PREFIXES]; bool prefixes_onlink[MAX_PREFIXES]; + + size_t n_rdnss; + struct in6_addr rdnss[MAX_RDNSS]; } G = { .rtnl_sock = -1, .icmp_sock = -1, @@ -505,10 +517,24 @@ static void send_advert(void) { }; } - struct iovec vec[3] = { + struct nd_opt_rdnss rdnss = {}; + uint8_t rdnss_ips[G.n_rdnss][16]; + + if (G.n_rdnss > 0) { + rdnss.nd_opt_rdnss_type = 25; + rdnss.nd_opt_rdnss_len = 1 + 2 * G.n_rdnss; + rdnss.nd_opt_rdnss_lifetime = htonl(AdvRDNSSLifetime); + + for (i = 0; i < G.n_rdnss; i++) + memcpy(rdnss_ips[i], G.rdnss[i].s6_addr, 16); + } + + struct iovec vec[5] = { { .iov_base = &advert, .iov_len = sizeof(advert) }, { .iov_base = &lladdr, .iov_len = sizeof(lladdr) }, { .iov_base = prefixes, .iov_len = sizeof(prefixes) }, + { .iov_base = &rdnss, .iov_len = sizeof(rdnss) }, + { .iov_base = rdnss_ips, .iov_len = sizeof(rdnss_ips) } }; struct sockaddr_in6 addr = { @@ -531,7 +557,7 @@ static void send_advert(void) { .msg_name = &addr, .msg_namelen = sizeof(addr), .msg_iov = vec, - .msg_iovlen = 3, + .msg_iovlen = G.n_rdnss > 0 ? 5 : 3, .msg_control = cbuf, .msg_controllen = 0, .msg_flags = 0, @@ -552,7 +578,21 @@ static void send_advert(void) { static void usage(void) { - fprintf(stderr, "Usage: uradvd [-h] -i -a/-p [ -a/-p ... ] [ --default-lifetime ]\n"); + fprintf(stderr, "Usage: uradvd [-h] -i -a/-p [ -a/-p ... ] [ --default-lifetime ] [ --rdnss ... ]\n"); +} + +static void add_rdnss(const char *ip) { + if (G.n_rdnss == MAX_RDNSS) + error(1, 0, "maximum number of RDNSS IPs is %i.", MAX_RDNSS); + + if (inet_pton(AF_INET6, ip, &G.rdnss[G.n_rdnss]) != 1) + goto error; + + G.n_rdnss++; + return; + + error: + error(1, 0, "invalid RDNSS IP address %s.", ip); } static void add_prefix(const char *prefix, bool adv_onlink) { @@ -594,6 +634,7 @@ static void parse_cmdline(int argc, char *argv[]) { static struct option long_options[] = { {"default-lifetime", required_argument, 0, 0}, + {"rdnss", required_argument, 0, 1}, {0, 0, 0, 0} }; @@ -611,6 +652,10 @@ static void parse_cmdline(int argc, char *argv[]) { break; + case 1: // --rdnss + add_rdnss(optarg); + break; + case 'i': if (G.ifname) error(1, 0, "multiple interfaces are not supported.");