From 58461b29bb2fbac41775a67ba317497edcdbbf90 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Thu, 16 Oct 2014 11:19:53 +0200 Subject: [PATCH] router: unicast RAs to RS senders by default --- src/router.c | 80 +++++++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/src/router.c b/src/router.c index a45a8cb..77972ab 100644 --- a/src/router.c +++ b/src/router.c @@ -31,7 +31,7 @@ static void forward_router_advertisement(uint8_t *data, size_t len); static void handle_icmpv6(void *addr, void *data, size_t len, struct interface *iface, void *dest); -static void send_router_advert(struct uloop_timeout *event); +static void trigger_router_advert(struct uloop_timeout *event); static void sigusr1_refresh(int signal); static struct odhcpd_event router_event = {{.fd = -1}, handle_icmpv6}; @@ -104,7 +104,7 @@ int setup_router_interface(struct interface *iface, bool enable) if (!enable) { if (iface->ra) - send_router_advert(&iface->timer_rs); + trigger_router_advert(&iface->timer_rs); } else { void *mreq = &all_routers; @@ -112,8 +112,8 @@ int setup_router_interface(struct interface *iface, bool enable) mreq = &all_nodes; forward_router_solicitation(iface); } else if (iface->ra == RELAYD_SERVER && !iface->master) { - iface->timer_rs.cb = send_router_advert; - send_router_advert(&iface->timer_rs); + iface->timer_rs.cb = trigger_router_advert; + trigger_router_advert(&iface->timer_rs); } if (iface->ra == RELAYD_RELAY || (iface->ra == RELAYD_SERVER && !iface->master)) @@ -168,26 +168,6 @@ static bool router_icmpv6_valid(struct sockaddr_in6 *source, uint8_t *data, size return opt == end; } -// Event handler for incoming ICMPv6 packets -static void handle_icmpv6(void *addr, void *data, size_t len, - struct interface *iface, _unused void *dest) -{ - 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); - } else if (iface->ra == RELAYD_RELAY) { // Relay mode - if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master) - forward_router_advertisement(data, len); - else if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master) - forward_router_solicitation(odhcpd_get_master_interface()); - } -} - // Detect whether a default route exists, also find the source prefixes static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len) @@ -227,11 +207,8 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len) // Router Advert server mode -static void send_router_advert(struct uloop_timeout *event) +static uint64_t send_router_advert(struct interface *iface, const struct in6_addr *from) { - struct interface *iface = - container_of(event, struct interface, timer_rs); - int mtu = odhcpd_get_interface_mtu(iface->ifname); if (mtu < 0) mtu = 1500; @@ -265,7 +242,7 @@ static void send_router_advert(struct uloop_timeout *event) uint64_t maxpreferred = 0; // If not shutdown - if (event->cb) { + if (iface->timer_rs.cb) { ipcnt = odhcpd_get_interface_addresses(iface->ifindex, addrs, ARRAY_SIZE(addrs)); @@ -385,10 +362,6 @@ static void send_router_advert(struct uloop_timeout *event) uint8_t name[]; } *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; @@ -443,9 +416,22 @@ static void send_router_advert(struct uloop_timeout *event) {&dns, (dns_cnt) ? sizeof(dns) : 0}, {dns_addr, dns_cnt * sizeof(*dns_addr)}, {search, search->len * 8}}; - struct sockaddr_in6 all_nodes = {AF_INET6, 0, 0, ALL_IPV6_NODES, 0}; + struct sockaddr_in6 dest = {AF_INET6, 0, 0, ALL_IPV6_NODES, 0}; + + if (from && !IN6_IS_ADDR_UNSPECIFIED(from)) + dest.sin6_addr = *from; + odhcpd_send(router_event.uloop.fd, - &all_nodes, iov, ARRAY_SIZE(iov), iface); + &dest, iov, ARRAY_SIZE(iov), iface); + + return maxpreferred; +} + + +static void trigger_router_advert(struct uloop_timeout *event) +{ + struct interface *iface = container_of(event, struct interface, timer_rs); + uint64_t maxpreferred = send_router_advert(iface, NULL); // Rearm timer if not shut down if (event->cb) { @@ -466,7 +452,29 @@ static void send_router_advert(struct uloop_timeout *event) int msecs; odhcpd_urandom(&msecs, sizeof(msecs)); msecs = (labs(msecs) % (maxinterval - mininterval)) + mininterval; - uloop_timeout_set(&iface->timer_rs, msecs); + uloop_timeout_set(event, msecs); + } +} + + +// Event handler for incoming ICMPv6 packets +static void handle_icmpv6(void *addr, void *data, size_t len, + struct interface *iface, _unused void *dest) +{ + struct icmp6_hdr *hdr = data; + struct sockaddr_in6 *from = addr; + + 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, &from->sin6_addr); + } else if (iface->ra == RELAYD_RELAY) { // Relay mode + if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master) + forward_router_advertisement(data, len); + else if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master) + forward_router_solicitation(odhcpd_get_master_interface()); } } -- 2.30.2