X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Frouter.c;h=dfbcf60dca73e4fb62f0b3e1b7eeb895f1cb971b;hp=83da938606fc165bf6b92c02400ffc102e66ab44;hb=84cfd09747332071c83de4882daecb9bfb80897b;hpb=0b68cabeb40d6e24a677a9332d3f3db163b5d723 diff --git a/src/router.c b/src/router.c index 83da938..dfbcf60 100644 --- a/src/router.c +++ b/src/router.c @@ -130,12 +130,50 @@ static void sigusr1_refresh(_unused int signal) uloop_timeout_set(&iface->timer_rs, 1000); } +static bool router_icmpv6_valid(struct sockaddr_in6 *source, uint8_t *data, size_t len) +{ + struct icmp6_hdr *hdr = (struct icmp6_hdr *)data; + struct icmpv6_opt *opt, *end = (struct icmpv6_opt*)&data[len]; + + /* Hoplimit is already checked in odhcpd_receive_packets */ + if (len < sizeof(*hdr) || hdr->icmp6_code) + return false; + + switch (hdr->icmp6_type) { + case ND_ROUTER_ADVERT: + if (!IN6_IS_ADDR_LINKLOCAL(&source->sin6_addr)) + return false; + + opt = (struct icmpv6_opt *)((struct nd_router_advert *)data + 1); + break; + + case ND_ROUTER_SOLICIT: + opt = (struct icmpv6_opt *)((struct nd_router_solicit *)data + 1); + break; + + default: + return false; + } + + icmpv6_for_each_option(opt, opt, end) + if (opt->type == ND_OPT_SOURCE_LINKADDR && + IN6_IS_ADDR_UNSPECIFIED(&source->sin6_addr) && + hdr->icmp6_type == ND_ROUTER_SOLICIT) + return false; + + // Check all options parsed successfully + return opt == end; +} // Event handler for incoming ICMPv6 packets -static void handle_icmpv6(_unused void *addr, void *data, size_t len, +static void handle_icmpv6(void *addr, void *data, size_t len, struct interface *iface) { struct icmp6_hdr *hdr = data; + + if (!router_icmpv6_valid(addr, data, len)) + return; + if ((iface->ra == RELAYD_SERVER && !iface->master)) { // Server mode if (hdr->icmp6_type == ND_ROUTER_SOLICIT) send_router_advert(&iface->timer_rs); @@ -219,7 +257,10 @@ static void send_router_advert(struct uloop_timeout *event) .lladdr = {ND_OPT_SOURCE_LINKADDR, 1, {0}}, .mtu = {ND_OPT_MTU, 1, 0, htonl(mtu)}, }; - adv.h.nd_ra_flags_reserved = ND_RA_FLAG_OTHER; + + if (iface->dhcpv6) + adv.h.nd_ra_flags_reserved = ND_RA_FLAG_OTHER; + if (iface->managed >= RELAYD_MANAGED_MFLAG) adv.h.nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; @@ -304,11 +345,6 @@ static void send_router_advert(struct uloop_timeout *event) adv.h.nd_ra_router_lifetime = 0; } - if (have_public && iface->deprecate_ula_if_public_avail) - for (size_t i = 0; i < cnt; ++i) - if ((adv.prefix[i].nd_opt_pi_prefix.s6_addr[0] & 0xfe) == 0xfc) - adv.prefix[i].nd_opt_pi_preferred_time = 0; - // DNS Recursive DNS if (iface->dns_cnt > 0) { dns_addr = iface->dns; @@ -415,12 +451,14 @@ static void send_router_advert(struct uloop_timeout *event) odhcpd_send(router_event.uloop.fd, &all_nodes, iov, ARRAY_SIZE(iov), iface); - // Rearm timer - int msecs; - odhcpd_urandom(&msecs, sizeof(msecs)); - msecs = (labs(msecs) % (1000 * (MaxRtrAdvInterval - - MinRtrAdvInterval))) + (MinRtrAdvInterval * 1000); - uloop_timeout_set(&iface->timer_rs, msecs); + // Rearm timer if not shut down + if (event->cb) { + int msecs; + odhcpd_urandom(&msecs, sizeof(msecs)); + msecs = (labs(msecs) % (1000 * (MaxRtrAdvInterval + - MinRtrAdvInterval))) + (MinRtrAdvInterval * 1000); + uloop_timeout_set(&iface->timer_rs, msecs); + } }