From: Roy Marples Date: Mon, 1 Jul 2013 19:23:19 +0000 (+0000) Subject: Fix dhcpcd owning the RA if the kernel has disabled RA but there X-Git-Tag: v6.0.3~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3566eb3cb5f7c1e59f87adb38da1f49906a7e151;p=thirdparty%2Fdhcpcd.git Fix dhcpcd owning the RA if the kernel has disabled RA but there is no directive in dhcpcd.conf --- diff --git a/dhcpcd.c b/dhcpcd.c index c2cb2eac..6b15de86 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -294,6 +294,7 @@ static void configure_interface1(struct interface *ifp) { struct if_options *ifo = ifp->options; + int ra_global, ra_iface; /* Do any platform specific configuration */ if_conf(ifp); @@ -313,8 +314,13 @@ configure_interface1(struct interface *ifp) /* We want to disable kernel interface RA as early as possible. */ if (ifo->options & DHCPCD_IPV6RS) { - if (check_ipv6(NULL) != 1 || check_ipv6(ifp->name) != 1) + ra_global = check_ipv6(NULL, options & DHCPCD_IPV6RA_OWN); + ra_iface = check_ipv6(ifp->name, + ifp->options->options & DHCPCD_IPV6RA_OWN); + if (ra_global == -1 || ra_iface == -1) ifo->options &= ~DHCPCD_IPV6RS; + else if (ra_iface == 0) + ifo->options |= DHCPCD_IPV6RA_OWN; } /* If we haven't specified a ClientID and our hardware address diff --git a/ipv6.c b/ipv6.c index 096996cc..f98ccad4 100644 --- a/ipv6.c +++ b/ipv6.c @@ -921,6 +921,8 @@ ipv6_build_dhcp_routes(struct rt6head *dnr, enum DH6S dstate) struct rt6 *rt; TAILQ_FOREACH(ifp, ifaces, next) { + if (!(ifp->options->options & DHCPCD_IPV6RA_OWN)) + continue; d6_state = D6_CSTATE(ifp); if (d6_state && d6_state->state == dstate) { TAILQ_FOREACH(addr, &d6_state->addrs, next) { @@ -941,9 +943,7 @@ ipv6_buildroutes(void) struct rt6head dnr, *nrs; struct rt6 *rt, *rtn, *or; uint8_t have_default; - - if (!(options & (DHCPCD_IPV6RA_OWN | DHCPCD_IPV6RA_OWN_DEFAULT))) - return; + unsigned long long o; TAILQ_INIT(&dnr); @@ -1017,9 +1017,10 @@ ipv6_buildroutes(void) while ((rt = TAILQ_LAST(routes, rt6head))) { TAILQ_REMOVE(routes, rt, next); if (find_route6(nrs, rt) == NULL) { + o = rt->iface->options->options; if (!have_default && - (options & DHCPCD_IPV6RA_OWN_DEFAULT) && - !(options & DHCPCD_IPV6RA_OWN) && + (o & DHCPCD_IPV6RA_OWN_DEFAULT) && + !(o & DHCPCD_IPV6RA_OWN) && RT_IS_DEFAULT(rt)) have_default = 1; /* no need to add it back to our routing table diff --git a/ipv6rs.c b/ipv6rs.c index 0d54b4e5..5969f627 100644 --- a/ipv6rs.c +++ b/ipv6rs.c @@ -912,7 +912,7 @@ ipv6rs_handledata(__unused void *arg) script_runreason(ifp, "TEST"); goto handle_flag; } - if (options & DHCPCD_IPV6RA_OWN) + if (ifp->options->options & DHCPCD_IPV6RA_OWN) ipv6ns_probeaddrs(&rap->addrs); ipv6_buildroutes(); diff --git a/platform-bsd.c b/platform-bsd.c index be535039..9bb2b863 100644 --- a/platform-bsd.c +++ b/platform-bsd.c @@ -118,52 +118,55 @@ ipv6_ra_flush(void) } int -check_ipv6(const char *ifname) +check_ipv6(const char *ifname, int own) { - static int ipv6_checked = 0; - int r; + static int set_restore = 0, forward_warned = 0, global_ra = 0; + int ra, forward; - /* BSD doesn't support these values per iface, so just return 1 */ + /* BSD doesn't support these values per iface, so just return + * the global ra setting */ if (ifname) - return 1; - - if (ipv6_checked) - return 1; - ipv6_checked = 1; + return global_ra; - r = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV); - if (r == -1) + ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV); + if (ra == -1) /* The sysctl probably doesn't exist, but this isn't an * error as such so just log it and continue */ syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, "IPV6CTL_ACCEPT_RTADV: %m"); - else if (r == 0) - options |= DHCPCD_IPV6RA_OWN; - else if (options & DHCPCD_IPV6RA_OWN) { + else if (ra != 0 && own) { syslog(LOG_INFO, "disabling Kernel IPv6 RA support"); if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1) { syslog(LOG_ERR, "IPV6CTL_ACCEPT_RTADV: %m"); - return 0; + return ra; + } + if (!set_restore) { + set_restore = 1; + atexit(restore_kernel_ra); } - atexit(restore_kernel_ra); + ra = 0; } - - r = get_inet6_sysctl(IPV6CTL_FORWARDING); - if (r == -1) - /* The sysctl probably doesn't exist, but this isn't an - * error as such so just log it and continue */ - syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, - "IPV6CTL_FORWARDING: %m"); - else if (r != 0) { - syslog(LOG_WARNING, - "Kernel is configured as a router, not a host"); - return 0; + if (ifname == NULL) + global_ra = ra; + + if (!forward_warned) { + forward = get_inet6_sysctl(IPV6CTL_FORWARDING); + if (forward == -1) + /* The sysctl probably doesn't exist, but this isn't an + * error as such so just log it and continue */ + syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, + "IPV6CTL_FORWARDING: %m"); + else if (forward != 0) { + forward_warned = 1; + syslog(LOG_WARNING, + "Kernel is configured as a router, not a host"); + } } /* Flush the kernel knowledge of advertised routers */ ipv6_ra_flush(); - return 1; + return ra; } int diff --git a/platform-linux.c b/platform-linux.c index f5bbbfc5..7c415d2f 100644 --- a/platform-linux.c +++ b/platform-linux.c @@ -176,10 +176,10 @@ restore_kernel_ra(void) } int -check_ipv6(const char *ifname) +check_ipv6(const char *ifname, int own) { static int ipv6_checked = 0; - int r, ex, i; + int ra, forward, ex, i; char path[256], *p, **nrest; if (ifname == NULL) { @@ -192,20 +192,18 @@ check_ipv6(const char *ifname) ex = 0; snprintf(path, sizeof(path), "%s/%s/accept_ra", prefix, ifname); - r = check_proc_int(path); - if (r == -1) + ra = check_proc_int(path); + if (ra == -1) /* The sysctl probably doesn't exist, but this isn't an * error as such so just log it and continue */ syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, "%s: %m", path); - else if (r == 0) - options |= DHCPCD_IPV6RA_OWN; - else if (options & DHCPCD_IPV6RA_OWN) { + else if (ra != 0 && own) { syslog(LOG_INFO, "%s: disabling Kernel IPv6 RA support", ifname); if (write_path(path, "0") == -1) { syslog(LOG_ERR, "write_path: %s: %m", path); - return 0; + return ra; } for (i = 0; i < nrestore; i++) if (strcmp(restore[i], ifname) == 0) @@ -231,22 +229,22 @@ check_ipv6(const char *ifname) } forward: - if (r != 2) { + if (ra != 2) { snprintf(path, sizeof(path), "%s/%s/forwarding", prefix, ifname); - r = check_proc_int(path); - if (r == -1) { + forward = check_proc_int(path); + if (forward == -1) { /* The sysctl probably doesn't exist, but this isn't an * error as such so just log it and continue */ syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, "%s: %m", path); - } else if (r != 0) { + } else if (forward != 0) { syslog(LOG_WARNING, "%s: configured as a router, not a host", ifname); return 0; } } - return 1; + return ra; } int diff --git a/platform.h b/platform.h index 5f469e43..36086b54 100644 --- a/platform.h +++ b/platform.h @@ -30,7 +30,7 @@ char *hardware_platform(void); #ifdef INET6 -int check_ipv6(const char *); +int check_ipv6(const char *, int); int ipv6_dadtransmits(const char *); #else #define check_ipv6(a) 0