]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-netlink: Use event socket wrapper for XFRM and networking events
authorTobias Brunner <tobias@strongswan.org>
Thu, 26 Jan 2023 16:50:51 +0000 (17:50 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 16 Feb 2023 12:25:35 +0000 (13:25 +0100)
src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c

index ddc7b1c2abe51ec790d608b6aa1de183d5bdc3b0..0a22692f1f9a9849d360030fde66c62f0571dac6 100644 (file)
  */
 #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",
index 9292b5ec224d129b9036eb6ad4c6027559cfa861..8040d1917b7a2b991c3fc45a1727f384a8c41970 100644 (file)
@@ -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)
        {