Mercurial > hg > dhcpcd
changeset 4532:23730414d0a6 draft
Merge branch 'master' into rbtree
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Fri, 14 Jun 2019 15:22:43 +0100 |
| parents | 578ac745c627 (current diff) a44c7ef76f2d (diff) |
| children | 33a7edb3a44a |
| files | src/dhcp6.c src/dhcpcd.c src/ipv6.c src/ipv6nd.c |
| diffstat | 7 files changed, 128 insertions(+), 96 deletions(-) [+] |
line wrap: on
line diff
--- a/hooks/20-resolv.conf Fri Jun 07 17:15:00 2019 +0100 +++ b/hooks/20-resolv.conf Fri Jun 14 15:22:43 2019 +0100 @@ -69,30 +69,26 @@ } # Extract any ND DNS options from the RA -# For now, we ignore the lifetime of the DNS options unless they -# are absent or zero. -# In this case they are removed from consideration. -# See draft-gont-6man-slaac-dns-config-issues-01 for issues -# regarding DNS option lifetime in ND messages. +# Obey the lifetimes eval_nd_dns() { - eval ltime=\$nd${i}_rdnss${j}_lifetime - if [ -z "$ltime" ] || [ "$ltime" = 0 ]; then - rdnss= - else + + eval rdnsstime=\$nd${i}_rdnss${j}_lifetime + [ -z "$rdnsstime" ] && return 1 + ltime=$(($rdnsstime - $offset)) + if [ "$ltime" -gt 0 ]; then eval rdnss=\$nd${i}_rdnss${j}_servers - fi - eval ltime=\$nd${i}_dnssl${j}_lifetime - if [ -z "$ltime" ] || [ "$ltime" = 0 ]; then - dnssl= - else - eval dnssl=\$nd${i}_dnssl${j}_search + [ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss" fi - [ -z "${rdnss}${dnssl}" ] && return 1 + eval dnssltime=\$nd${i}_dnssl${j}_lifetime + [ -z "$dnssltime" ] && return 1 + ltime=$(($dnssltime - $offset)) + if [ "$ltime" -gt 0 ]; then + eval dnssl=\$nd${i}_dnssl${j}_search + [ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl" + fi - [ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss" - [ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl" j=$(($j + 1)) return 0 } @@ -106,12 +102,16 @@ i=1 j=1 while true; do + eval acquired=\$nd${i}_acquired + [ -z "$acquired" ] && break + eval now=\$nd${i}_now + [ -z "$now" ] && break + offset=$(($now - $acquired)) while true; do eval_nd_dns || break done i=$(($i + 1)) j=1 - eval_nd_dns || break done [ -n "$new_rdnss" ] && \ new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss"
--- a/hooks/30-hostname Fri Jun 07 17:15:00 2019 +0100 +++ b/hooks/30-hostname Fri Jun 14 15:22:43 2019 +0100 @@ -80,7 +80,7 @@ set_hostname_vars if [ -n "$old_fqdn" ]; then - if ${hfqdn} || ! ${hsort}; then + if ${hfqdn} || ! ${hshort}; then [ "$hostname" = "$old_fqdn" ] else [ "$hostname" = "${old_fqdn%%.*}" ]
--- a/src/dhcp6.c Fri Jun 07 17:15:00 2019 +0100 +++ b/src/dhcp6.c Fri Jun 14 15:22:43 2019 +0100 @@ -3918,21 +3918,6 @@ } void -dhcp6_dropnondelegates(struct interface *ifp) -{ - -#ifndef SMALL - if (dhcp6_hasprefixdelegation(ifp)) - return; -#endif - if (D6_CSTATE(ifp) == NULL) - return; - - loginfox("%s: dropping DHCPv6 due to no valid routers", ifp->name); - dhcp6_drop(ifp, "EXPIRE6"); -} - -void dhcp6_abort(struct interface *ifp) { struct dhcp6_state *state;
--- a/src/dhcp6.h Fri Jun 07 17:15:00 2019 +0100 +++ b/src/dhcp6.h Fri Jun 14 15:22:43 2019 +0100 @@ -235,7 +235,6 @@ int dhcp6_dadcompleted(const struct interface *); void dhcp6_abort(struct interface *); void dhcp6_drop(struct interface *, const char *); -void dhcp6_dropnondelegates(struct interface *ifp); int dhcp6_dump(struct interface *); #endif /* DHCP6 */
--- a/src/dhcpcd.c Fri Jun 07 17:15:00 2019 +0100 +++ b/src/dhcpcd.c Fri Jun 14 15:22:43 2019 +0100 @@ -738,9 +738,6 @@ #ifdef INET dhcp_abort(ifp); #endif -#ifdef INET6 - ipv6nd_expire(ifp, 0); -#endif #ifdef DHCP6 dhcp6_abort(ifp); #endif
--- a/src/ipv6.c Fri Jun 07 17:15:00 2019 +0100 +++ b/src/ipv6.c Fri Jun 14 15:22:43 2019 +0100 @@ -2235,15 +2235,14 @@ } static int -inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx, int expired, - bool *have_default) +inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) { struct rt *rt; struct ra *rap; const struct ipv6_addr *addr; TAILQ_FOREACH(rap, ctx->ra_routers, next) { - if (rap->expired != expired) + if (rap->expired) continue; TAILQ_FOREACH(addr, &rap->addrs, next) { if (addr->prefix_vltime == 0) @@ -2254,14 +2253,13 @@ rt_proto_add(routes, rt); } } - if (rap->lifetime) { - rt = inet6_makerouter(rap); - if (rt) { - rt->rt_dflags |= RTDF_RA; - if (rt_proto_add(routes, rt) && have_default) - *have_default = true; - } - } + if (rap->lifetime == 0) + continue; + rt = inet6_makerouter(rap); + if (rt == NULL) + continue; + rt->rt_dflags |= RTDF_RA; + rt_proto_add(routes, rt); } return 0; } @@ -2295,15 +2293,13 @@ bool inet6_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes) { - bool have_default; /* Should static take priority? */ if (inet6_staticroutes(routes, ctx) == -1) return false; /* First add reachable routers and their prefixes */ - have_default = false; - if (inet6_raroutes(routes, ctx, 0, &have_default) == -1) + if (inet6_raroutes(routes, ctx) == -1) return false; #ifdef DHCP6 @@ -2316,21 +2312,5 @@ return false; #endif -#ifdef HAVE_ROUTE_METRIC - /* If we have an unreachable router, we really do need to remove the - * route to it beause it could be a lower metric than a reachable - * router. Of course, we should at least have some routers if all - * are unreachable. */ - if (!have_default) { -#endif - /* Add our non-reachable routers and prefixes - * Unsure if this is needed, but it's a close match to kernel - * behaviour */ - if (inet6_raroutes(routes, ctx, 1, NULL) == -1) - return false; -#ifdef HAVE_ROUTE_METRIC - } -#endif - return true; }
--- a/src/ipv6nd.c Fri Jun 07 17:15:00 2019 +0100 +++ b/src/ipv6nd.c Fri Jun 14 15:22:43 2019 +0100 @@ -105,6 +105,9 @@ #define RTPREF_RESERVED (-2) #define RTPREF_INVALID (-3) /* internal */ +#define EXPIRED_MAX 5 /* Remember 5 expired routers to avoid + logspam. */ + #define MIN_RANDOM_FACTOR 500 /* millisecs */ #define MAX_RANDOM_FACTOR 1500 /* millisecs */ #define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */ @@ -382,9 +385,6 @@ else { logwarnx("%s: no IPv6 Routers available", ifp->name); ipv6nd_drop(ifp); -#ifdef DHCP6 - dhcp6_dropnondelegates(ifp); -#endif } } @@ -1231,6 +1231,10 @@ break; case ND_OPT_MTU: + if (len < sizeof(mtu)) { + logerrx("%s: short MTU option", ifp->name); + break; + } memcpy(&mtu, p, sizeof(mtu)); mtu.nd_opt_mtu_mtu = ntohl(mtu.nd_opt_mtu_mtu); if (mtu.nd_opt_mtu_mtu < IPV6_MMTU) { @@ -1242,6 +1246,10 @@ break; case ND_OPT_RDNSS: + if (len < sizeof(rdnss)) { + logerrx("%s: short RDNSS option", ifp->name); + break; + } memcpy(&rdnss, p, sizeof(rdnss)); if (rdnss.nd_opt_rdnss_lifetime && rdnss.nd_opt_rdnss_len > 1) @@ -1478,11 +1486,12 @@ * from the prefix information options as well. */ j = 0; TAILQ_FOREACH(ia, &rap->addrs, next) { - if (!(ia->flags & IPV6_AF_AUTOCONF) + if (!(ia->flags & IPV6_AF_AUTOCONF) || #ifdef IPV6_AF_TEMPORARY - || ia->flags & IPV6_AF_TEMPORARY + ia->flags & IPV6_AF_TEMPORARY || #endif - ) + !(ia->flags & IPV6_AF_ADDED) || + ia->prefix_vltime == 0) continue; j++; if (env) { @@ -1520,9 +1529,16 @@ struct timespec now, lt, expire, next; bool expired, valid, validone; struct ipv6_addr *ia; -#ifdef DHCP6 - bool anyvalid = false; + size_t len, olen; + uint8_t *p; + struct nd_opt_hdr ndo; +#if 0 + struct nd_opt_prefix_info pi; #endif + struct nd_opt_dnssl dnssl; + struct nd_opt_rdnss rdnss; + uint32_t ltime; + size_t nexpired = 0; ifp = arg; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1537,8 +1553,7 @@ lt.tv_sec = (time_t)rap->lifetime; lt.tv_nsec = 0; timespecadd(&rap->acquired, <, &expire); - if (rap->lifetime == 0 || timespeccmp(&now, &expire, >)) - { + if (timespeccmp(&now, &expire, >)) { if (!rap->expired) { logwarnx("%s: %s: router expired", ifp->name, rap->sfrom); @@ -1589,34 +1604,90 @@ } } - /* XXX FixMe! - * We need to extract the lifetime from each option and check - * if that has expired or not. - * If it has, zero the option out in the returned data. */ + /* Work out expiry for ND options */ + len = rap->data_len - sizeof(struct nd_router_advert); + for (p = rap->data + sizeof(struct nd_router_advert); + len >= sizeof(ndo); + p += olen, len -= olen) + { + memcpy(&ndo, p, sizeof(ndo)); + olen = (size_t)(ndo.nd_opt_len * 8); + if (olen > len) { + errno = EINVAL; + break; + } + + if (has_option_mask(rap->iface->options->nomasknd, + ndo.nd_opt_type)) + continue; - /* No valid lifetimes are left on the RA, so we might - * as well punt it. */ - if (!valid && !validone) + switch (ndo.nd_opt_type) { + /* Prefix info is already checked in the above loop. */ +#if 0 + case ND_OPT_PREFIX_INFORMATION: + if (len < sizeof(pi)) + break; + memcpy(&pi, p, sizeof(pi)); + ltime = pi.nd_opt_pi_valid_time; + break; +#endif + case ND_OPT_DNSSL: + if (len < sizeof(dnssl)) + break; + memcpy(&dnssl, p, sizeof(dnssl)); + ltime = dnssl.nd_opt_dnssl_lifetime; + break; + case ND_OPT_RDNSS: + if (len < sizeof(rdnss)) + break; + memcpy(&rdnss, p, sizeof(rdnss)); + ltime = rdnss.nd_opt_rdnss_lifetime; + break; + default: + continue; + } + + if (ltime == 0) + continue; + if (ltime == ND6_INFINITE_LIFETIME) { + validone = true; + continue; + } + + lt.tv_sec = (time_t)ntohl(ltime); + lt.tv_nsec = 0; + timespecadd(&rap->acquired, <, &expire); + if (timespeccmp(&now, &expire, >)) { + expired = true; + continue; + } + + timespecsub(&expire, &now, <); + if (!timespecisset(&next) || + timespeccmp(&next, <, >)) + { + next = lt; + validone = true; + } + } + + if (valid || validone) + continue; + + /* Router has expired. Let's not keep a lot of them. + * We should work out if all the options have expired .... */ + if (++nexpired > EXPIRED_MAX) ipv6nd_free_ra(rap); -#ifdef DHCP6 - else - anyvalid = true; -#endif } if (timespecisset(&next)) eloop_timeout_add_tv(ifp->ctx->eloop, &next, ipv6nd_expirera, ifp); if (expired) { + logwarnx("%s: part of Router Advertisement expired", ifp->name); rt_build(ifp->ctx, AF_INET6); script_runreason(ifp, "ROUTERADVERT"); } - -#ifdef DHCP6 - /* No valid routers? Kill any DHCPv6. */ - if (!anyvalid) - dhcp6_dropnondelegates(ifp); -#endif } void
