X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Frouter.c;h=dfbcf60dca73e4fb62f0b3e1b7eeb895f1cb971b;hp=a213c84739778e43db0dd670937ff49cc5d17189;hb=84cfd09747332071c83de4882daecb9bfb80897b;hpb=3f417e55d5208df5b91aa9b101657bbc7a461614 diff --git a/src/router.c b/src/router.c index a213c84..dfbcf60 100644 --- a/src/router.c +++ b/src/router.c @@ -130,23 +130,19 @@ static void sigusr1_refresh(_unused int signal) uloop_timeout_set(&iface->timer_rs, 1000); } -static int router_icmpv6_valid(struct sockaddr_in6 *source, uint8_t *data, size_t len) +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; - size_t optlen = len - sizeof(*hdr); + struct icmpv6_opt *opt, *end = (struct icmpv6_opt*)&data[len]; /* Hoplimit is already checked in odhcpd_receive_packets */ - if (len < sizeof(*hdr)) - return 0; - - if (hdr->icmp6_code) - return 0; + 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 0; + return false; opt = (struct icmpv6_opt *)((struct nd_router_advert *)data + 1); break; @@ -156,29 +152,17 @@ static int router_icmpv6_valid(struct sockaddr_in6 *source, uint8_t *data, size_ break; default: - return 0; + return false; } - while (optlen > 0) { - size_t l = opt->len << 3; - - if (optlen < sizeof(*opt)) - return 0; - - if (l > optlen || l == 0) - return 0; + 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; - if (opt->type == ND_OPT_SOURCE_LINKADDR && IN6_IS_ADDR_UNSPECIFIED(&source->sin6_addr) && - hdr->icmp6_type == ND_ROUTER_SOLICIT) { - return 0; - } - - opt = (struct icmpv6_opt *)(((uint8_t *)opt) + l); - - optlen -= l; - } - - return 1; + // Check all options parsed successfully + return opt == end; } // Event handler for incoming ICMPv6 packets @@ -186,7 +170,7 @@ 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; @@ -265,7 +249,7 @@ static void send_router_advert(struct uloop_timeout *event) struct { struct nd_router_advert h; - struct nd_opt_slla lladdr; + struct icmpv6_opt lladdr; struct nd_opt_mtu mtu; struct nd_opt_prefix_info prefix[RELAYD_MAX_PREFIXES]; } adv = { @@ -273,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; @@ -281,7 +268,7 @@ static void send_router_advert(struct uloop_timeout *event) adv.h.nd_ra_flags_reserved |= ND_RA_PREF_LOW; else if (iface->route_preference > 0) adv.h.nd_ra_flags_reserved |= ND_RA_PREF_HIGH; - odhcpd_get_mac(iface, adv.lladdr.addr); + odhcpd_get_mac(iface, adv.lladdr.data); // If not currently shutting down struct odhcpd_ipaddr addrs[RELAYD_MAX_PREFIXES]; @@ -358,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; @@ -373,7 +355,14 @@ static void send_router_advert(struct uloop_timeout *event) if (!dns_addr) dns_cnt = 0; - struct nd_opt_recursive_dns dns = {ND_OPT_RECURSIVE_DNS, (1 + (2 * dns_cnt)), 0, 0, htonl(dns_time)}; + struct { + uint8_t type; + uint8_t len; + uint8_t pad; + uint8_t pad2; + uint32_t lifetime; + } dns = {ND_OPT_RECURSIVE_DNS, (1 + (2 * dns_cnt)), 0, 0, htonl(dns_time)}; + // DNS Search options @@ -462,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); + } } @@ -502,12 +493,11 @@ static void forward_router_advertisement(uint8_t *data, size_t len) icmpv6_for_each_option(opt, &adv[1], end) { if (opt->type == ND_OPT_SOURCE_LINKADDR) { // Store address of source MAC-address - mac_ptr = ((struct nd_opt_slla *)opt)->addr; + mac_ptr = opt->data; } else if (opt->type == ND_OPT_RECURSIVE_DNS && opt->len > 1) { - struct nd_opt_recursive_dns *dns = (struct nd_opt_recursive_dns *)opt; // Check if we have to rewrite DNS - dns_ptr = (struct in6_addr *)&dns[1]; - dns_count = (dns->len - 1) / 2; + dns_ptr = (struct in6_addr*)&opt->data[6]; + dns_count = (opt->len - 1) / 2; } }