From: Tobias Brunner Date: Thu, 26 Jan 2023 16:43:18 +0000 (+0100) Subject: kernel-netlink: Add simple wrapper for Netlink event sockets X-Git-Tag: android-2.4.1~4^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cb0bdb847d83f0335c4eef8ca6d12e4ef56e8eee;p=thirdparty%2Fstrongswan.git kernel-netlink: Add simple wrapper for Netlink event sockets --- diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c index 8af3016f6d..9292b5ec22 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c @@ -79,9 +79,6 @@ #define ROUTING_TABLE_PRIO 0 #endif -/** multicast groups (for groups > 31 setsockopt has to be used) */ -#define nl_group(group) (1 << (group - 1)) - ENUM(rt_msg_names, RTM_NEWLINK, RTM_GETRULE, "RTM_NEWLINK", "RTM_DELLINK", diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c index abb9d16f80..71905e3c9c 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2022 Tobias Brunner + * Copyright (C) 2008-2023 Tobias Brunner * Copyright (C) 2014 Martin Willi * * Copyright (C) secunet Security Networks AG @@ -58,6 +58,7 @@ #endif typedef struct private_netlink_socket_t private_netlink_socket_t; +typedef struct private_netlink_event_socket_t private_netlink_event_socket_t; /** * Private variables and functions of netlink_socket_t class. @@ -125,6 +126,37 @@ struct private_netlink_socket_t { bool ignore_retransmit_errors; }; +/** + * Private data of netlink_event_socket_t class + */ +struct private_netlink_event_socket_t { + + /** + * Public interface + */ + netlink_event_socket_t public; + + /** + * Registered callback + */ + netlink_event_cb_t cb; + + /** + * User data to pass to callback + */ + void *user; + + /** + * Netlink socket + */ + int socket; + + /** + * Buffer size for received Netlink messages + */ + u_int buflen; +}; + /** * #definable hook to simulate request message loss */ @@ -700,6 +732,92 @@ netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names, return &this->public; } +CALLBACK(watch_event, bool, + private_netlink_event_socket_t *this, int fd, watcher_event_t event) +{ + char buf[this->buflen]; + struct nlmsghdr *hdr = (struct nlmsghdr*)buf; + struct sockaddr_nl addr; + socklen_t addr_len = sizeof(addr); + int len; + + len = recvfrom(this->socket, buf, sizeof(buf), MSG_DONTWAIT, + (struct sockaddr*)&addr, &addr_len); + if (len < 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + { + DBG1(DBG_KNL, "netlink event read error: %s", strerror(errno)); + } + return TRUE; + } + else if (addr.nl_pid != 0) + { /* ignore non-kernel messages */ + return TRUE; + } + + while (NLMSG_OK(hdr, len)) + { + this->cb(this->user, hdr); + hdr = NLMSG_NEXT(hdr, len); + } + return TRUE; +} + +METHOD(netlink_event_socket_t, destroy_event, void, + private_netlink_event_socket_t *this) +{ + if (this->socket != -1) + { + lib->watcher->remove(lib->watcher, this->socket); + close(this->socket); + } + free(this); +} + +/* + * Described in header + */ +netlink_event_socket_t *netlink_event_socket_create(int protocol, uint32_t groups, + netlink_event_cb_t cb, void *user) +{ + private_netlink_event_socket_t *this; + struct sockaddr_nl addr = { + .nl_family = AF_NETLINK, + .nl_groups = groups, + }; + + INIT(this, + .public = { + .destroy = _destroy_event, + }, + .cb = cb, + .user = user, + .buflen = netlink_get_buflen(), + ); + + this->socket = socket(AF_NETLINK, SOCK_RAW, protocol); + if (this->socket == -1) + { + DBG1(DBG_KNL, "unable to create netlink event socket: %s (%d)", + strerror(errno), errno); + destroy_event(this); + return NULL; + } + + if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr))) + { + DBG1(DBG_KNL, "unable to bind netlink event socket: %s (%d)", + strerror(errno), errno); + destroy_event(this); + return NULL; + } + + lib->watcher->add(lib->watcher, this->socket, WATCHER_READ, watch_event, this); + + return &this->public; +} + /* * Described in header */ diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.h b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.h index cec3e5e5b9..9638129704 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.h +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2022 Tobias Brunner + * Copyright (C) 2008-2023 Tobias Brunner * * Copyright (C) secunet Security Networks AG * @@ -40,7 +40,16 @@ typedef union { u_char bytes[KERNEL_NETLINK_BUFSIZE]; } netlink_buf_t __attribute__((aligned(RTA_ALIGNTO))); +/** + * Callback function for netlink events. + * + * @param user user data, as passed to constructor + * @param hdr received netlink message + */ +typedef void (*netlink_event_cb_t)(void *user, struct nlmsghdr *hdr); + typedef struct netlink_socket_t netlink_socket_t; +typedef struct netlink_event_socket_t netlink_event_socket_t; /** * Wrapper around a netlink socket. @@ -80,6 +89,45 @@ struct netlink_socket_t { netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names, bool parallel); +/** + * Wrapper around a bound netlink event socket. + */ +struct netlink_event_socket_t { + + /** + * Destroy the event socket. + */ + void (*destroy)(netlink_event_socket_t *this); +}; + +/** + * Create a netlink_event_socket_t object. + * + * @param protocol protocol type (e.g. NETLINK_XFRM or NETLINK_ROUTE) + * @param groups event groups to bind (use nl_group()) + * @param cb callback to invoke for each event + * @param user user data passed to callback + */ +netlink_event_socket_t *netlink_event_socket_create(int protocol, uint32_t groups, + netlink_event_cb_t cb, void *user); + +/** + * Helper to create bitmask for Netlink multicast groups. + * + * For groups > 31, setsockopt() with NETLINK_ADD_MEMBERSHIP has to be used, + * which is currently not supported by the event socket. + */ +static inline uint32_t nl_group(uint32_t group) +{ + if (group > 31) + { + DBG1(DBG_KNL, "netlink multicast group %d currently not supported", + group); + return 0; + } + return group ? (1 << (group - 1)) : 0; +} + /** * Creates an rtattr and adds it to the given netlink message. *