From: Tobias Brunner Date: Thu, 26 Jan 2023 16:50:51 +0000 (+0100) Subject: kernel-netlink: Use event socket wrapper for XFRM and networking events X-Git-Tag: android-2.4.1~4^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77a5c9514c343b7d2513cd182855257abaf92df0;p=thirdparty%2Fstrongswan.git kernel-netlink: Use event socket wrapper for XFRM and networking events --- diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index ddc7b1c2ab..0a22692f1f 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -108,11 +108,6 @@ */ #define XFRM_LIMIT(x) ((x) == 0 ? XFRM_INF : (x)) -/** - * Create ORable bitfield of XFRM NL groups - */ -#define XFRMNLGRP(x) (1<<(XFRMNLGRP_##x-1)) - /** * Returns a pointer to the first rtattr following the nlmsghdr *nlh and the * 'usual' netlink data x like 'struct xfrm_usersa_info' @@ -344,7 +339,7 @@ struct private_kernel_netlink_ipsec_t { /** * Netlink xfrm socket to receive acquire and expire events */ - int socket_xfrm_events; + netlink_event_socket_t *socket_xfrm_events; /** * Whether to install routes along policies @@ -1111,67 +1106,28 @@ static void process_mapping(private_kernel_netlink_ipsec_t *this, } } -/** - * Receives events from kernel - */ -static bool receive_events(private_kernel_netlink_ipsec_t *this, int fd, - watcher_event_t event) -{ - char response[netlink_get_buflen()]; - struct nlmsghdr *hdr = (struct nlmsghdr*)response; - struct sockaddr_nl addr; - socklen_t addr_len = sizeof(addr); - int len; - - len = recvfrom(this->socket_xfrm_events, response, sizeof(response), - MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len); - if (len < 0) - { - switch (errno) - { - case EINTR: - /* interrupted, try again */ - return TRUE; - case EAGAIN: - /* no data ready, select again */ - return TRUE; - default: - DBG1(DBG_KNL, "unable to receive from XFRM event socket: %s " - "(%d)", strerror(errno), errno); - sleep(1); - return TRUE; - } - } - - if (addr.nl_pid != 0) - { /* not from kernel. not interested, try another one */ - return TRUE; - } - - while (NLMSG_OK(hdr, len)) +CALLBACK(receive_events, void, + private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr) +{ + switch (hdr->nlmsg_type) { - switch (hdr->nlmsg_type) - { - case XFRM_MSG_ACQUIRE: - process_acquire(this, hdr); - break; - case XFRM_MSG_EXPIRE: - process_expire(this, hdr); - break; - case XFRM_MSG_MIGRATE: - process_migrate(this, hdr); - break; - case XFRM_MSG_MAPPING: - process_mapping(this, hdr); - break; - default: - DBG1(DBG_KNL, "received unknown event from XFRM event " - "socket: %d", hdr->nlmsg_type); - break; - } - hdr = NLMSG_NEXT(hdr, len); + case XFRM_MSG_ACQUIRE: + process_acquire(this, hdr); + break; + case XFRM_MSG_EXPIRE: + process_expire(this, hdr); + break; + case XFRM_MSG_MIGRATE: + process_migrate(this, hdr); + break; + case XFRM_MSG_MAPPING: + process_mapping(this, hdr); + break; + default: + DBG1(DBG_KNL, "received unknown event from XFRM event " + "socket: %d", hdr->nlmsg_type); + break; } - return TRUE; } METHOD(kernel_ipsec_t, get_features, kernel_feature_t, @@ -3637,11 +3593,7 @@ METHOD(kernel_ipsec_t, destroy, void, array_destroy_function(this->bypass, (array_callback_t)remove_port_bypass, this); - if (this->socket_xfrm_events > 0) - { - lib->watcher->remove(lib->watcher, this->socket_xfrm_events); - close(this->socket_xfrm_events); - } + DESTROY_IF(this->socket_xfrm_events); DESTROY_IF(this->socket_xfrm); enumerator = this->policies->create_enumerator(this->policies); while (enumerator->enumerate(enumerator, &policy, &policy)) @@ -3764,7 +3716,7 @@ static void setup_spd_hash_thresh(private_kernel_netlink_ipsec_t *this, kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() { private_kernel_netlink_ipsec_t *this; - struct sockaddr_nl addr; + uint32_t groups; INIT(this, .public = { @@ -3816,29 +3768,15 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() setup_spd_hash_thresh(this, "ipv4", XFRMA_SPD_IPV4_HTHRESH, 32); setup_spd_hash_thresh(this, "ipv6", XFRMA_SPD_IPV6_HTHRESH, 128); - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - - /* create and bind XFRM socket for ACQUIRE, EXPIRE, MIGRATE & MAPPING */ - this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); - if (this->socket_xfrm_events <= 0) + groups = nl_group(XFRMNLGRP_ACQUIRE) | nl_group(XFRMNLGRP_EXPIRE) | + nl_group(XFRMNLGRP_MIGRATE) | nl_group(XFRMNLGRP_MAPPING); + this->socket_xfrm_events = netlink_event_socket_create(NETLINK_XFRM, groups, + receive_events, this); + if (!this->socket_xfrm_events) { - DBG1(DBG_KNL, "unable to create XFRM event socket: %s (%d)", - strerror(errno), errno); - destroy(this); - return NULL; - } - addr.nl_groups = XFRMNLGRP(ACQUIRE) | XFRMNLGRP(EXPIRE) | - XFRMNLGRP(MIGRATE) | XFRMNLGRP(MAPPING); - if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr))) - { - DBG1(DBG_KNL, "unable to bind XFRM event socket: %s (%d)", - strerror(errno), errno); destroy(this); return NULL; } - lib->watcher->add(lib->watcher, this->socket_xfrm_events, WATCHER_READ, - (watcher_cb_t)receive_events, this); netlink_find_offload_feature(lib->settings->get_str(lib->settings, "%s.plugins.kernel-netlink.hw_offload_feature_interface", diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c index 9292b5ec22..8040d1917b 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c @@ -340,9 +340,9 @@ struct private_kernel_netlink_net_t { netlink_socket_t *socket; /** - * Netlink rt socket to receive address change events + * Netlink rt event socket */ - int socket_events; + netlink_event_socket_t *socket_events; /** * earliest time of the next roam event @@ -1448,76 +1448,36 @@ static void process_rule(private_kernel_netlink_net_t *this, #endif } -/** - * Receives events from kernel - */ -static bool receive_events(private_kernel_netlink_net_t *this, int fd, - watcher_event_t event) +CALLBACK(receive_events, void, + private_kernel_netlink_net_t *this, struct nlmsghdr *hdr) { - char response[netlink_get_buflen()]; - struct nlmsghdr *hdr = (struct nlmsghdr*)response; - struct sockaddr_nl addr; - socklen_t addr_len = sizeof(addr); - int len; - - len = recvfrom(this->socket_events, response, sizeof(response), - MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len); - if (len < 0) - { - switch (errno) - { - case EINTR: - /* interrupted, try again */ - return TRUE; - case EAGAIN: - /* no data ready, select again */ - return TRUE; - default: - DBG1(DBG_KNL, "unable to receive from RT event socket %s (%d)", - strerror(errno), errno); - sleep(1); - return TRUE; - } - } - - if (addr.nl_pid != 0) - { /* not from kernel. not interested, try another one */ - return TRUE; - } - - while (NLMSG_OK(hdr, len)) + switch (hdr->nlmsg_type) { - /* looks good so far, dispatch netlink message */ - switch (hdr->nlmsg_type) - { - case RTM_NEWADDR: - case RTM_DELADDR: - process_addr(this, hdr, TRUE); - break; - case RTM_NEWLINK: - case RTM_DELLINK: - process_link(this, hdr, TRUE); - break; - case RTM_NEWROUTE: - case RTM_DELROUTE: - if (this->process_route) - { - process_route(this, hdr); - } - break; - case RTM_NEWRULE: - case RTM_DELRULE: - if (this->process_rules) - { - process_rule(this, hdr); - } - break; - default: - break; - } - hdr = NLMSG_NEXT(hdr, len); + case RTM_NEWADDR: + case RTM_DELADDR: + process_addr(this, hdr, TRUE); + break; + case RTM_NEWLINK: + case RTM_DELLINK: + process_link(this, hdr, TRUE); + break; + case RTM_NEWROUTE: + case RTM_DELROUTE: + if (this->process_route) + { + process_route(this, hdr); + } + break; + case RTM_NEWRULE: + case RTM_DELRULE: + if (this->process_rules) + { + process_rule(this, hdr); + } + break; + default: + break; } - return TRUE; } /** enumerator over addresses */ @@ -3053,11 +3013,7 @@ METHOD(kernel_net_t, destroy, void, manage_rule(this, RTM_DELRULE, AF_INET6, this->routing_table, this->routing_table_prio); } - if (this->socket_events > 0) - { - lib->watcher->remove(lib->watcher, this->socket_events); - close(this->socket_events); - } + DESTROY_IF(this->socket_events); enumerator = this->routes->ht.create_enumerator(&this->routes->ht); while (enumerator->enumerate(enumerator, NULL, (void**)&route)) { @@ -3093,7 +3049,7 @@ kernel_netlink_net_t *kernel_netlink_net_create() { private_kernel_netlink_net_t *this; enumerator_t *enumerator; - struct sockaddr_nl addr; + uint32_t groups; char *exclude; INIT(this, @@ -3186,40 +3142,26 @@ kernel_netlink_net_t *kernel_netlink_net_create() enumerator->destroy(enumerator); } - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - - /* create and bind RT socket for events (address/interface/route changes) */ - this->socket_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (this->socket_events < 0) - { - DBG1(DBG_KNL, "unable to create RT event socket: %s (%d)", - strerror(errno), errno); - destroy(this); - return NULL; - } - addr.nl_groups = nl_group(RTNLGRP_IPV4_IFADDR) | - nl_group(RTNLGRP_IPV6_IFADDR) | - nl_group(RTNLGRP_LINK); + groups = nl_group(RTNLGRP_IPV4_IFADDR) | + nl_group(RTNLGRP_IPV6_IFADDR) | + nl_group(RTNLGRP_LINK); if (this->process_route) { - addr.nl_groups |= nl_group(RTNLGRP_IPV4_ROUTE) | - nl_group(RTNLGRP_IPV6_ROUTE); + groups |= nl_group(RTNLGRP_IPV4_ROUTE) | + nl_group(RTNLGRP_IPV6_ROUTE); } if (this->process_rules) { - addr.nl_groups |= nl_group(RTNLGRP_IPV4_RULE) | - nl_group(RTNLGRP_IPV6_RULE); + groups |= nl_group(RTNLGRP_IPV4_RULE) | + nl_group(RTNLGRP_IPV6_RULE); } - if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr))) + this->socket_events = netlink_event_socket_create(NETLINK_ROUTE, groups, + receive_events, this); + if (!this->socket_events) { - DBG1(DBG_KNL, "unable to bind RT event socket: %s (%d)", - strerror(errno), errno); destroy(this); return NULL; } - lib->watcher->add(lib->watcher, this->socket_events, WATCHER_READ, - (watcher_cb_t)receive_events, this); if (init_address_list(this) != SUCCESS) {