From d83414f67d17426fb49c80317b52babd6125a3c6 Mon Sep 17 00:00:00 2001 From: Antoine Damhet Date: Tue, 13 Feb 2024 20:01:10 +0100 Subject: [PATCH] netlink: cleanup interfaces upon removal Previously, when an interface was removed radvd did not release it's multicast membership leaking kernel resources leading to a potential out of memory failure of the `setsockopt([...], IPV6_ADD_MEMBERSHIP, [...])` call. Signed-off-by: Antoine Damhet --- netlink.c | 12 +++++++++--- netlink.h | 2 +- radvd.c | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/netlink.c b/netlink.c index 36f6ac7..14af756 100644 --- a/netlink.c +++ b/netlink.c @@ -207,13 +207,13 @@ int netlink_get_device_addr_len(struct Interface *iface) return addr_len; } -void process_netlink_msg(int sock, struct Interface *ifaces) +void process_netlink_msg(int netlink_sock, struct Interface *ifaces, int icmp_sock) { char buf[4096]; struct iovec iov = {buf, sizeof(buf)}; struct sockaddr_nl sa; struct msghdr msg = {.msg_name=(void *)&sa, .msg_namelen=sizeof(sa), .msg_iov=&iov, .msg_iovlen=1, .msg_control=NULL, .msg_controllen=0, .msg_flags=0}; - int len = recvmsg(sock, &msg, 0); + int len = recvmsg(netlink_sock, &msg, 0); if (len == -1) { flog(LOG_ERR, "netlink: recvmsg failed: %s", strerror(errno)); } @@ -259,7 +259,13 @@ void process_netlink_msg(int sock, struct Interface *ifaces) break; } if (iface) { - touch_iface(iface); + if (nh->nlmsg_type == RTM_DELLINK) { + dlog(LOG_INFO, 4, "netlink: %s removed, cleaning up", iface->props.name); + cleanup_iface(icmp_sock, iface); + } + else { + touch_iface(iface); + } } } else if (nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) { diff --git a/netlink.h b/netlink.h index 606fd35..553d0a9 100644 --- a/netlink.h +++ b/netlink.h @@ -19,6 +19,6 @@ int netlink_get_address_lifetimes(struct AdvPrefix const *prefix, unsigned int *preferred_lft, unsigned int *valid_lft); int netlink_get_device_addr_len(struct Interface *iface); -void process_netlink_msg(int sock, struct Interface *ifaces); +void process_netlink_msg(int netlink_sock, struct Interface *ifaces, int icmp_sock); int netlink_socket(void); int prefix_match (struct AdvPrefix const *prefix, struct in6_addr *addr); diff --git a/radvd.c b/radvd.c index 5769d89..3784b76 100644 --- a/radvd.c +++ b/radvd.c @@ -532,7 +532,7 @@ static struct Interface *main_loop(int sock, struct Interface *ifaces, char cons if (rc > 0) { #ifdef HAVE_NETLINK if (fds[1].revents & POLLIN) { - process_netlink_msg(fds[1].fd, ifaces); + process_netlink_msg(fds[1].fd, ifaces, sock); } else if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) { flog(LOG_WARNING, "socket error on fds[1].fd"); }