X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Frouter.c;h=a213c84739778e43db0dd670937ff49cc5d17189;hp=bb7ddcd27e5c1f045ce90998f2fb96006a867f23;hb=3f417e55d5208df5b91aa9b101657bbc7a461614;hpb=7117854698ba7c77da5823fc673f44e6db0fee5f diff --git a/src/router.c b/src/router.c index bb7ddcd..a213c84 100644 --- a/src/router.c +++ b/src/router.c @@ -130,12 +130,66 @@ 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) +{ + struct icmp6_hdr *hdr = (struct icmp6_hdr *)data; + struct icmpv6_opt *opt; + size_t optlen = len - sizeof(*hdr); + + /* Hoplimit is already checked in odhcpd_receive_packets */ + if (len < sizeof(*hdr)) + return 0; + + if (hdr->icmp6_code) + return 0; + + switch (hdr->icmp6_type) { + case ND_ROUTER_ADVERT: + if (!IN6_IS_ADDR_LINKLOCAL(&source->sin6_addr)) + return 0; + + 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 0; + } + + while (optlen > 0) { + size_t l = opt->len << 3; + + if (optlen < sizeof(*opt)) + return 0; + + if (l > optlen || l == 0) + return 0; + + 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; +} // 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); @@ -169,7 +223,7 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len) char line[512], ifname[16]; bool found_default = false; - struct odhcpd_ipaddr p = {IN6ADDR_ANY_INIT, 0, 0, 0}; + struct odhcpd_ipaddr p = {IN6ADDR_ANY_INIT, 0, false, 0, 0, 0}; while (fgets(line, sizeof(line), fp_route)) { uint32_t rflags; if (sscanf(line, "00000000000000000000000000000000 00 " @@ -211,7 +265,7 @@ static void send_router_advert(struct uloop_timeout *event) struct { struct nd_router_advert h; - struct icmpv6_opt lladdr; + struct nd_opt_slla lladdr; struct nd_opt_mtu mtu; struct nd_opt_prefix_info prefix[RELAYD_MAX_PREFIXES]; } adv = { @@ -227,7 +281,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.data); + odhcpd_get_mac(iface, adv.lladdr.addr); // If not currently shutting down struct odhcpd_ipaddr addrs[RELAYD_MAX_PREFIXES]; @@ -254,7 +308,7 @@ static void send_router_advert(struct uloop_timeout *event) for (ssize_t i = 0; i < ipcnt; ++i) { struct odhcpd_ipaddr *addr = &addrs[i]; - if (addr->prefix > 64) + if (addr->prefix > 64 || addr->has_class) continue; // Address not suitable if (addr->preferred > MaxPreferredTime) @@ -319,14 +373,7 @@ static void send_router_advert(struct uloop_timeout *event) if (!dns_addr) dns_cnt = 0; - 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)}; - + struct nd_opt_recursive_dns dns = {ND_OPT_RECURSIVE_DNS, (1 + (2 * dns_cnt)), 0, 0, htonl(dns_time)}; // DNS Search options @@ -352,7 +399,12 @@ static void send_router_advert(struct uloop_timeout *event) uint8_t pad2; uint32_t lifetime; uint8_t name[]; - } *search = malloc(sizeof(*search) + search_padded); + } *search = alloca(sizeof(*search) + search_padded); + + if (!search) { + syslog(LOG_ERR, "Alloca failed for dns search on interface %s", iface->ifname); + return; + } search->type = ND_OPT_DNS_SEARCH; search->len = search_len ? ((sizeof(*search) + search_padded) / 8) : 0; search->pad = 0; @@ -409,7 +461,6 @@ static void send_router_advert(struct uloop_timeout *event) struct sockaddr_in6 all_nodes = {AF_INET6, 0, 0, ALL_IPV6_NODES, 0}; odhcpd_send(router_event.uloop.fd, &all_nodes, iov, ARRAY_SIZE(iov), iface); - free(search); // Rearm timer int msecs; @@ -451,11 +502,12 @@ 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 = opt->data; + mac_ptr = ((struct nd_opt_slla *)opt)->addr; } 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*)&opt->data[6]; - dns_count = (opt->len - 1) / 2; + dns_ptr = (struct in6_addr *)&dns[1]; + dns_count = (dns->len - 1) / 2; } }