From d420f49396c627ce1072b83170889baf0720bc8b Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 16 Nov 2016 14:47:46 +0100 Subject: [PATCH] Add option to ignore default lifetime for RDNSS records 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 --- src/odhcp6c.c | 11 +++++++++-- src/odhcp6c.h | 4 ++++ src/ra.c | 29 +++++++++++++++++------------ src/ra.h | 2 +- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/odhcp6c.c b/src/odhcp6c.c index ba568bd..e97ad26 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -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 Maximum timeout for DHCPv6-SOLICIT (120)\n" " -m Minimum time between accepting updates (30)\n" + " -L Ignore default lifetime for RDNSS records\n" "\nInvocation options:\n" " -p Set pidfile (/var/run/odhcp6c.pid)\n" " -d Daemonize\n" diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 5ebea29..2a10113 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -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, diff --git a/src/ra.c b/src/ra.c index 89dc58b..1c38968 100644 --- 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; + } } } diff --git a/src/ra.h b/src/ra.h index 3beac68..3634f3c 100644 --- 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); -- 2.30.2