Add option to ignore default lifetime for RDNSS records
authorMatthias Schiffer <mschiffer@universe-factory.net>
Wed, 16 Nov 2016 13:47:46 +0000 (14:47 +0100)
committerHans Dedecker <dedeckeh@gmail.com>
Tue, 3 Jan 2017 21:34:17 +0000 (22:34 +0100)
While RFC6106 mandates that the RDNSS lifetime is capped to the default
lifetime, this behaviour is often undesirable. In particular, it prevents
accepting RDNSS records from RAs that don't also advertise a default route
(set the default lifetime to 0).

Therefore, make it possible to opt out of this behaviour and respect the
RDNSS lifetime independently of the default lifetime using the new command
line switch -L.

Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
src/odhcp6c.c
src/odhcp6c.h
src/ra.c
src/ra.h

index ba568bd4499acd962e975edebc7ace89561bcfef..e97ad267f192e5b6e421658f8dae2e92eea61d46 100644 (file)
@@ -74,8 +74,9 @@ int main(_unused int argc, char* const argv[])
        int logopt = LOG_PID;
        int c;
        unsigned int client_options = DHCPV6_CLIENT_FQDN | DHCPV6_ACCEPT_RECONFIGURE;
+       unsigned int ra_options = RA_RDNSS_DEFAULT_LIFETIME;
 
-       while ((c = getopt(argc, argv, "S::N:V:P:FB:c:i:r:Ru:s:kt:m:hedp:fav")) != -1) {
+       while ((c = getopt(argc, argv, "S::N:V:P:FB:c:i:r:Ru:s:kt:m:Lhedp:fav")) != -1) {
                switch (c) {
                case 'S':
                        allow_slaac_only = (optarg) ? atoi(optarg) : -1;
@@ -193,6 +194,10 @@ int main(_unused int argc, char* const argv[])
                        min_update_interval = atoi(optarg);
                        break;
 
+               case 'L':
+                       ra_options &= ~RA_RDNSS_DEFAULT_LIFETIME;
+                       break;
+
                case 'e':
                        logopt |= LOG_PERROR;
                        break;
@@ -244,7 +249,8 @@ int main(_unused int argc, char* const argv[])
 
        if ((urandom_fd = open("/dev/urandom", O_CLOEXEC | O_RDONLY)) < 0 ||
                        init_dhcpv6(ifname, client_options, sol_timeout) ||
-                       ra_init(ifname, &ifid) || script_init(script, ifname)) {
+                       ra_init(ifname, &ifid, ra_options) ||
+                       script_init(script, ifname)) {
                syslog(LOG_ERR, "failed to initialize: %s", strerror(errno));
                return 3;
        }
@@ -443,6 +449,7 @@ static int usage(void)
        "       -k              Don't send a RELEASE when stopping\n"
        "       -t <seconds>    Maximum timeout for DHCPv6-SOLICIT (120)\n"
        "       -m <seconds>    Minimum time between accepting updates (30)\n"
+       "       -L              Ignore default lifetime for RDNSS records\n"
        "\nInvocation options:\n"
        "       -p <pidfile>    Set pidfile (/var/run/odhcp6c.pid)\n"
        "       -d              Daemonize\n"
index 5ebea2949b7b591494833e5ae7a76161b0e5caa2..2a10113852481a209d5e039ee041c020afc2f118 100644 (file)
@@ -282,6 +282,10 @@ enum dhcpv6_mode {
        DHCPV6_STATEFUL
 };
 
+enum ra_config {
+       RA_RDNSS_DEFAULT_LIFETIME = 1,
+};
+
 enum odhcp6c_ia_mode {
        IA_MODE_NONE,
        IA_MODE_TRY,
index 89dc58b960b557b3e3a6d651b11b1a6a5fa49c7c..1c3896887ec9136fa21c2ad522b96fa116801070 100644 (file)
--- a/src/ra.c
+++ b/src/ra.c
@@ -55,6 +55,7 @@ static int if_index = 0;
 static char if_name[IF_NAMESIZE] = {0};
 static volatile int rs_attempt = 0;
 static struct in6_addr lladdr = IN6ADDR_ANY_INIT;
+static unsigned int ra_options = 0;
 
 struct {
        struct icmp6_hdr hdr;
@@ -67,8 +68,10 @@ struct {
 
 static void ra_send_rs(int signal __attribute__((unused)));
 
-int ra_init(const char *ifname, const struct in6_addr *ifid)
+int ra_init(const char *ifname, const struct in6_addr *ifid, unsigned int options)
 {
+       ra_options = options;
+
        const pid_t ourpid = getpid();
        sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
        if (sock < 0)
@@ -443,17 +446,19 @@ bool ra_process(void)
                        }
                }
 
-               int states[2] = {STATE_RA_DNS, STATE_RA_SEARCH};
-               for (size_t i = 0; i < 2; ++i) {
-                       size_t ra_dns_len;
-                       uint8_t *start = odhcp6c_get_state(states[i], &ra_dns_len);
-                       for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start;
-                                               (uint8_t*)c < &start[ra_dns_len] &&
-                                               (uint8_t*)odhcp6c_next_entry(c) <= &start[ra_dns_len];
-                                               c = odhcp6c_next_entry(c))
-                               if (IN6_ARE_ADDR_EQUAL(&c->router, &from.sin6_addr) &&
-                                               c->valid > router_valid)
-                                       c->valid = router_valid;
+               if (ra_options & RA_RDNSS_DEFAULT_LIFETIME) {
+                       int states[2] = {STATE_RA_DNS, STATE_RA_SEARCH};
+                       for (size_t i = 0; i < 2; ++i) {
+                               size_t ra_dns_len;
+                               uint8_t *start = odhcp6c_get_state(states[i], &ra_dns_len);
+                               for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start;
+                                                       (uint8_t*)c < &start[ra_dns_len] &&
+                                                       (uint8_t*)odhcp6c_next_entry(c) <= &start[ra_dns_len];
+                                                       c = odhcp6c_next_entry(c))
+                                       if (IN6_ARE_ADDR_EQUAL(&c->router, &from.sin6_addr) &&
+                                                       c->valid > router_valid)
+                                               c->valid = router_valid;
+                       }
                }
        }
 
index 3beac68576a04bcf0b41df0f400b343a29b78ef6..3634f3cb4e1f45d8c6699914ad20c6767fb85d5e 100644 (file)
--- a/src/ra.h
+++ b/src/ra.h
@@ -34,6 +34,6 @@ struct icmpv6_opt {
        (void*)(opt + opt->len) <= (void*)(end); opt += opt->len)
 
 
-int ra_init(const char *ifname, const struct in6_addr *ifid);
+int ra_init(const char *ifname, const struct in6_addr *ifid, unsigned int options);
 bool ra_link_up(void);
 bool ra_process(void);