From fd3e3bbc461fcbbaefff9339da2e9b6c85a5b4a1 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Tue, 7 Jul 2015 16:01:13 +0200 Subject: [PATCH] router: also send RAs to every known neighbor --- src/ndp.c | 2 +- src/odhcpd.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/odhcpd.h | 4 ++++ src/router.c | 17 +++++++++++++++- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/ndp.c b/src/ndp.c index 027e9ab..a6f8427 100644 --- a/src/ndp.c +++ b/src/ndp.c @@ -356,7 +356,7 @@ static void handle_rtnetlink(_unused void *addr, void *data, size_t len, // Data to retrieve size_t rta_offset = (is_route) ? sizeof(*rtm) : (is_addr) ? - sizeof(*ifa) : sizeof(*ndm); + sizeof(struct ifaddrmsg) : sizeof(*ndm); uint16_t atype = (is_route) ? RTA_DST : (is_addr) ? IFA_ADDRESS : NDA_DST; ssize_t alen = NLMSG_PAYLOAD(nh, rta_offset); struct in6_addr *addr = NULL; diff --git a/src/odhcpd.c b/src/odhcpd.c index aad5b37..3fb3009 100644 --- a/src/odhcpd.c +++ b/src/odhcpd.c @@ -194,6 +194,61 @@ ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest, } +int odhcpd_iterate_interface_neighbors(const struct interface *iface, + void(*cb_neigh)(const struct in6_addr *addr, + const struct interface *iface, void *data), void *data) +{ + struct { + struct nlmsghdr nhm; + struct ndmsg ndm; + } req = {{sizeof(req), RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP, + ++rtnl_seq, 0}, {AF_INET6, 0, 0, iface->ifindex, 0, 0, 0}}; + + if (send(rtnl_socket, &req, sizeof(req), 0) < (ssize_t)sizeof(req)) + return -1; + + uint8_t buf[8192]; + ssize_t len = 0; + + for (struct nlmsghdr *nhm = NULL; ; nhm = NLMSG_NEXT(nhm, len)) { + while (len < 0 || !NLMSG_OK(nhm, (size_t)len)) { + len = recv(rtnl_socket, buf, sizeof(buf), 0); + nhm = (struct nlmsghdr*)buf; + if (len < 0 || !NLMSG_OK(nhm, (size_t)len)) { + if (errno == EINTR) + continue; + else + return -1; + } + } + + if (nhm->nlmsg_type != RTM_NEWNEIGH) + break; + + struct ndmsg *ndm = NLMSG_DATA(nhm); + if (ndm->ndm_ifindex != iface->ifindex || + (ndm->ndm_state & NUD_FAILED)) + continue; + + struct rtattr *rta = (struct rtattr*)&ndm[1]; + size_t alen = NLMSG_PAYLOAD(nhm, sizeof(*ndm)); + + while (RTA_OK(rta, alen)) { + if (rta->rta_type == NDA_DST) { + // TODO + cb_neigh(NULL, iface, data); + break; + } else { + rta = RTA_NEXT(rta, alen); + } + } + + } + + return 0; +} + + // Detect an IPV6-address currently assigned to the given interface ssize_t odhcpd_get_interface_addresses(int ifindex, struct odhcpd_ipaddr *addrs, size_t cnt) diff --git a/src/odhcpd.h b/src/odhcpd.h index 5944661..dcd2d14 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -202,6 +202,10 @@ void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len); int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits); void odhcpd_bmemcpy(void *av, const void *bv, size_t bits); +int odhcpd_iterate_interface_neighbors(const struct interface *iface, + void(*cb_neigh)(const struct in6_addr *addr, + const struct interface *iface, void *data), void *data); + int config_parse_interface(void *data, size_t len, const char *iname, bool overwrite); #ifdef WITH_UBUS diff --git a/src/router.c b/src/router.c index f942d8f..718f170 100644 --- a/src/router.c +++ b/src/router.c @@ -37,6 +37,7 @@ static void sigusr1_refresh(int signal); static struct odhcpd_event router_event = {{.fd = -1}, handle_icmpv6}; static FILE *fp_route = NULL; +#define RA_IOV_LEN 6 int init_router(void) @@ -205,6 +206,18 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len) return found_default; } +// Unicsat RAs +static void send_neigh_ra(const struct in6_addr *addr, + const struct interface *iface, void *data) +{ + struct sockaddr_in6 dest = { + .sin6_family = AF_INET6, + .sin6_addr = *addr, + .sin6_scope_id = iface->ifindex, + }; + odhcpd_send(router_event.uloop.fd, &dest, data, RA_IOV_LEN, iface); +} + // Router Advert server mode static uint64_t send_router_advert(struct interface *iface, const struct in6_addr *from) @@ -443,7 +456,8 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add .data = {0, 0, maxival >> 24, maxival >> 16, maxival >> 8, maxival} }; - struct iovec iov[] = {{&adv, (uint8_t*)&adv.prefix[cnt] - (uint8_t*)&adv}, + struct iovec iov[RA_IOV_LEN] = { + {&adv, (uint8_t*)&adv.prefix[cnt] - (uint8_t*)&adv}, {&routes, routes_cnt * sizeof(*routes)}, {&dns, (dns_cnt) ? sizeof(dns) : 0}, {dns_addr, dns_cnt * sizeof(*dns_addr)}, @@ -457,6 +471,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add odhcpd_send(router_event.uloop.fd, &dest, iov, ARRAY_SIZE(iov), iface); + odhcpd_iterate_interface_neighbors(iface, send_neigh_ra, iov); return msecs; } -- 2.25.1