From e60710d1fe0c5bf19b9acf9b116e0645e8e114d1 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 16 Nov 2015 12:10:24 +0100 Subject: [PATCH] Handle netlink ENOBUFS events --- src/ndp.c | 25 +++++++++++++++++++++++-- src/odhcpd.c | 13 ++++++++++++- src/odhcpd.h | 1 + src/router.c | 2 +- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/ndp.c b/src/ndp.c index 7f63f96..95eb18f 100644 --- a/src/ndp.c +++ b/src/ndp.c @@ -38,10 +38,11 @@ static void handle_solicit(void *addr, void *data, size_t len, struct interface *iface, void *dest); static void handle_rtnetlink(void *addr, void *data, size_t len, struct interface *iface, void *dest); +static void catch_rtnetlink(int error); static uint32_t rtnl_seqid = 0; static int ping_socket = -1; -static struct odhcpd_event rtnl_event = {{.fd = -1}, handle_rtnetlink}; +static struct odhcpd_event rtnl_event = {{.fd = -1}, handle_rtnetlink, catch_rtnetlink}; // Filter ICMPv6 messages of type neighbor soliciation @@ -60,10 +61,15 @@ static const struct sock_fprog bpf_prog = {sizeof(bpf) / sizeof(*bpf), bpf}; // Initialize NDP-proxy int init_ndp(void) { + int val = 256 * 1024; + // Setup netlink socket if ((rtnl_event.uloop.fd = odhcpd_open_rtnl()) < 0) return -1; + if (setsockopt(rtnl_event.uloop.fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val))) + setsockopt(rtnl_event.uloop.fd, SOL_SOCKET, SO_RCVBUFFORCE, &val, sizeof(val)); + // Receive netlink neighbor and ip-address events uint32_t group = RTNLGRP_IPV6_IFADDR; setsockopt(rtnl_event.uloop.fd, SOL_NETLINK, @@ -81,7 +87,7 @@ int init_ndp(void) return -1; } - int val = 2; + val = 2; setsockopt(ping_socket, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val)); // This is required by RFC 4861 @@ -491,3 +497,18 @@ static void handle_rtnetlink(_unused void *addr, void *data, size_t len, if (dump_neigh) dump_neigh_table(false); } + +static void catch_rtnetlink(int error) +{ + if (error == ENOBUFS) { + struct { + struct nlmsghdr nh; + struct ifaddrmsg ifa; + } req2 = { + {sizeof(req2), RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP, + ++rtnl_seqid, 0}, + {.ifa_family = AF_INET6} + }; + send(rtnl_event.uloop.fd, &req2, sizeof(req2), MSG_DONTWAIT); + } +} diff --git a/src/odhcpd.c b/src/odhcpd.c index 9c7f27c..0c9542c 100644 --- a/src/odhcpd.c +++ b/src/odhcpd.c @@ -367,6 +367,16 @@ static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int even struct sockaddr_nl nl; } addr; + if (u->error) { + int ret = -1; + socklen_t ret_len = sizeof(ret); + getsockopt(u->fd, SOL_SOCKET, SO_ERROR, &ret, &ret_len); + u->error = false; + if (e->handle_error) + e->handle_error(ret); + return; + } + while (true) { struct iovec iov = {data_buf, sizeof(data_buf)}; struct msghdr msg = { @@ -446,7 +456,8 @@ static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int even int odhcpd_register(struct odhcpd_event *event) { event->uloop.cb = odhcpd_receive_packets; - return uloop_fd_add(&event->uloop, ULOOP_READ); + return uloop_fd_add(&event->uloop, ULOOP_READ | + ((event->handle_error) ? ULOOP_ERROR_CB : 0)); } void odhcpd_process(struct odhcpd_event *event) diff --git a/src/odhcpd.h b/src/odhcpd.h index 81f4bee..fd43dfe 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -62,6 +62,7 @@ struct odhcpd_event { struct uloop_fd uloop; void (*handle_dgram)(void *addr, void *data, size_t len, struct interface *iface, void *dest_addr); + void (*handle_error)(int error); }; diff --git a/src/router.c b/src/router.c index 74d8a09..9907824 100644 --- a/src/router.c +++ b/src/router.c @@ -34,7 +34,7 @@ static void handle_icmpv6(void *addr, void *data, size_t len, 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}; +static struct odhcpd_event router_event = {{.fd = -1}, handle_icmpv6, NULL}; static FILE *fp_route = NULL; #define RA_IOV_LEN 6 -- 2.30.2