Pass sockets to bypass to kernel interface, allowing us to register them dynamically
authorMartin Willi <martin@revosec.ch>
Tue, 23 Feb 2010 16:28:23 +0000 (16:28 +0000)
committerMartin Willi <martin@revosec.ch>
Fri, 26 Feb 2010 10:44:33 +0000 (11:44 +0100)
src/charon/kernel/kernel_interface.c
src/charon/kernel/kernel_interface.h
src/charon/kernel/kernel_ipsec.h
src/charon/network/socket.h
src/charon/network/socket_manager.c
src/charon/network/socket_manager.h
src/charon/plugins/kernel_klips/kernel_klips_ipsec.c
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
src/charon/plugins/socket_default/socket_default_socket.c
src/charon/plugins/socket_raw/socket_raw_socket.c

index e9fb81e..64a43a7 100644 (file)
@@ -241,6 +241,15 @@ METHOD(kernel_interface_t, del_route, status_t,
                                                                src_ip, if_name);
 }
 
+METHOD(kernel_interface_t, bypass_socket, bool,
+       private_kernel_interface_t *this, int fd, int family)
+{
+       if (!this->ipsec)
+       {
+               return FALSE;
+       }
+       return this->ipsec->bypass_socket(this->ipsec, fd, family);
+}
 
 METHOD(kernel_interface_t, get_address_by_ts, status_t,
        private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip)
@@ -361,6 +370,7 @@ kernel_interface_t *kernel_interface_create()
                        .del_ip = _del_ip,
                        .add_route = _add_route,
                        .del_route = _del_route,
+                       .bypass_socket = _bypass_socket,
 
                        .get_address_by_ts = _get_address_by_ts,
                        .add_ipsec_interface = _add_ipsec_interface,
index c39246e..4a62e76 100644 (file)
@@ -333,6 +333,15 @@ struct kernel_interface_t {
                                                                host_t *gateway, host_t *src_ip, char *if_name);
 
        /**
+        * Set up a bypass policy for a given socket.
+        *
+        * @param fd                    socket file descriptor to setup policy for
+        * @param family                protocol family of the socket
+        * @return                              TRUE of policy set up successfully
+        */
+       bool (*bypass_socket)(kernel_interface_t *this, int fd, int family);
+
+       /**
         * manager methods
         */
 
index 73ad29b..300464c 100644 (file)
@@ -265,6 +265,15 @@ struct kernel_ipsec_t {
                                                        bool unrouted);
 
        /**
+        * Install a bypass policy for the given socket.
+        *
+        * @param fd                    socket file descriptor to setup policy for
+        * @param family                protocol family of the socket
+        * @return                              TRUE of policy set up successfully
+        */
+       bool (*bypass_socket)(kernel_ipsec_t *this, int fd, int family);
+
+       /**
         * Destroy the implementation.
         */
        void (*destroy) (kernel_ipsec_t *this);
index 798d341..5c5a4ed 100644 (file)
@@ -59,13 +59,6 @@ struct socket_t {
         *                                              - FAILED when unable to send
         */
        status_t (*send) (socket_t *this, packet_t *packet);
-
-       /**
-        * Enumerate all underlying socket file descriptors.
-        *
-        * @return                              enumerator over (int fd, int family, int port)
-        */
-       enumerator_t *(*create_enumerator) (socket_t *this);
 };
 
 #endif /** SOCKET_H_ @}*/
index 5bd9356..0dbce4b 100644 (file)
@@ -81,21 +81,6 @@ METHOD(socket_manager_t, sender, status_t,
        return status;
 }
 
-METHOD(socket_manager_t, create_enumerator, enumerator_t*,
-       private_socket_manager_t *this)
-{
-       socket_t *socket;
-
-       this->lock->read_lock(this->lock);
-       if (this->sockets->get_first(this->sockets, (void**)&socket) != SUCCESS)
-       {
-               this->lock->unlock(this->lock);
-               return enumerator_create_empty();
-       }
-       return enumerator_create_cleaner(socket->create_enumerator(socket),
-                                                                        (void*)this->lock->unlock, this->lock);
-}
-
 METHOD(socket_manager_t, add_socket, void,
        private_socket_manager_t *this, socket_t *socket)
 {
@@ -131,7 +116,6 @@ socket_manager_t *socket_manager_create()
                .public = {
                        .send = _sender,
                        .receive = _receiver,
-                       .create_enumerator = _create_enumerator,
                        .add_socket = _add_socket,
                        .remove_socket = _remove_socket,
                        .destroy = _destroy,
index da38f56..b33d5c7 100644 (file)
@@ -51,13 +51,6 @@ struct socket_manager_t {
        status_t (*send) (socket_manager_t *this, packet_t *packet);
 
        /**
-        * Enumerate all underlying socket file descriptors of the active socket.
-        *
-        * @return                              enumerator over (int fd, int family, int port)
-        */
-       enumerator_t *(*create_enumerator) (socket_manager_t *this);
-
-       /**
         * Register a socket implementation.
         */
        void (*add_socket)(socket_manager_t *this, socket_t *socket);
index 21f6b2a..c99b721 100644 (file)
@@ -2556,6 +2556,13 @@ static status_t register_pfkey_socket(private_kernel_klips_ipsec_t *this, u_int8
        return SUCCESS;
 }
 
+METHOD(kernel_ipsec_t, bypass_socket, bool,
+       private_kernel_klips_ipsec_t *this, int fd, int family)
+{
+       /* KLIPS does not need a bypass policy for IKE */
+       return TRUE;
+}
+
 METHOD(kernel_ipsec_t, destroy, void,
        private_kernel_klips_ipsec_t *this)
 {
@@ -2589,6 +2596,7 @@ kernel_klips_ipsec_t *kernel_klips_ipsec_create()
                        .add_policy = _add_policy,
                        .query_policy = _query_policy,
                        .del_policy = _del_policy,
+                       .bypass_socket = _bypass_socket,
                        .destroy = _destroy,
                },
                .policies = linked_list_create(),
index e5f7ac1..c8bcfd6 100644 (file)
@@ -1892,6 +1892,47 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        return SUCCESS;
 }
 
+METHOD(kernel_ipsec_t, bypass_socket, bool,
+       private_kernel_netlink_ipsec_t *this, int fd, int family)
+{
+       struct xfrm_userpolicy_info policy;
+       u_int sol, ipsec_policy;
+
+       switch (family)
+       {
+               case AF_INET:
+                       sol = SOL_IP;
+                       ipsec_policy = IP_XFRM_POLICY;
+                       break;
+               case AF_INET6:
+                       sol = SOL_IPV6;
+                       ipsec_policy = IPV6_XFRM_POLICY;
+                       break;
+               default:
+                       return FALSE;
+       }
+
+       memset(&policy, 0, sizeof(policy));
+       policy.action = XFRM_POLICY_ALLOW;
+       policy.sel.family = family;
+
+       policy.dir = XFRM_POLICY_OUT;
+       if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+       {
+               DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
+                        strerror(errno));
+               return FALSE;
+       }
+       policy.dir = XFRM_POLICY_IN;
+       if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+       {
+               DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
+                        strerror(errno));
+               return FALSE;
+       }
+       return TRUE;
+}
+
 METHOD(kernel_ipsec_t, destroy, void,
        private_kernel_netlink_ipsec_t *this)
 {
@@ -1912,60 +1953,6 @@ METHOD(kernel_ipsec_t, destroy, void,
        free(this);
 }
 
-/**
- * Add bypass policies for IKE on the sockets used by charon
- */
-static bool add_bypass_policies()
-{
-       int fd, family, port;
-       enumerator_t *sockets;
-       bool status = TRUE;
-
-       sockets = charon->socket->create_enumerator(charon->socket);
-       while (sockets->enumerate(sockets, &fd, &family, &port))
-       {
-               struct xfrm_userpolicy_info policy;
-               u_int sol, ipsec_policy;
-
-               switch (family)
-               {
-                       case AF_INET:
-                               sol = SOL_IP;
-                               ipsec_policy = IP_XFRM_POLICY;
-                               break;
-                       case AF_INET6:
-                               sol = SOL_IPV6;
-                               ipsec_policy = IPV6_XFRM_POLICY;
-                               break;
-                       default:
-                               continue;
-               }
-
-               memset(&policy, 0, sizeof(policy));
-               policy.action = XFRM_POLICY_ALLOW;
-               policy.sel.family = family;
-
-               policy.dir = XFRM_POLICY_OUT;
-               if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
-               {
-                       DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
-                                strerror(errno));
-                       status = FALSE;
-                       break;
-               }
-               policy.dir = XFRM_POLICY_IN;
-               if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
-               {
-                       DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
-                                strerror(errno));
-                       status = FALSE;
-                       break;
-               }
-       }
-       sockets->destroy(sockets);
-       return status;
-}
-
 /*
  * Described in header.
  */
@@ -1986,6 +1973,7 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
                        .add_policy = _add_policy,
                        .query_policy = _query_policy,
                        .del_policy = _del_policy,
+                       .bypass_socket = _bypass_socket,
                        .destroy = _destroy,
                },
                .policies = hashtable_create((hashtable_hash_t)policy_hash,
@@ -2020,13 +2008,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
        {
                charon->kill(charon, "unable to bind XFRM event socket");
        }
-
-       /* add bypass policies on the sockets used by charon */
-       if (!add_bypass_policies())
-       {
-               charon->kill(charon, "unable to add bypass policies on sockets");
-       }
-
        this->job = callback_job_create((callback_job_cb_t)receive_events,
                                                                        this, NULL, NULL);
        charon->processor->queue_job(charon->processor, (job_t*)this->job);
index b92cbb7..b64e41c 100644 (file)
@@ -2044,75 +2044,62 @@ static status_t register_pfkey_socket(private_kernel_pfkey_ipsec_t *this,
        return SUCCESS;
 }
 
-METHOD(kernel_ipsec_t, destroy, void,
-       private_kernel_pfkey_ipsec_t *this)
-{
-       this->job->cancel(this->job);
-       close(this->socket);
-       close(this->socket_events);
-       this->policies->destroy_function(this->policies, (void*)policy_entry_destroy);
-       this->mutex->destroy(this->mutex);
-       this->mutex_pfkey->destroy(this->mutex_pfkey);
-       free(this);
-}
-
-/**
- * Add bypass policies for IKE on the sockets of charon
- */
-static bool add_bypass_policies(private_kernel_pfkey_ipsec_t *this)
+METHOD(kernel_ipsec_t, bypass_socket, bool,
+       private_kernel_pfkey_ipsec_t *this, int fd, int family)
 {
-       int fd, family, port;
-       enumerator_t *sockets;
-       bool status = TRUE;
+       struct sadb_x_policy policy;
+       u_int sol, ipsec_policy;
 
-       sockets = charon->socket->create_enumerator(charon->socket);
-       while (sockets->enumerate(sockets, &fd, &family, &port))
+       switch (family)
        {
-               struct sadb_x_policy policy;
-               u_int sol, ipsec_policy;
-
-               switch (family)
+               case AF_INET:
                {
-                       case AF_INET:
-                       {
-                               sol = SOL_IP;
-                               ipsec_policy = IP_IPSEC_POLICY;
-                               break;
-                       }
-                       case AF_INET6:
-                       {
-                               sol = SOL_IPV6;
-                               ipsec_policy = IPV6_IPSEC_POLICY;
-                               break;
-                       }
-                       default:
-                               continue;
-               }
-
-               memset(&policy, 0, sizeof(policy));
-               policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
-               policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
-               policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
-
-               policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
-               if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
-               {
-                       DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
-                                strerror(errno));
-                       status = FALSE;
+                       sol = SOL_IP;
+                       ipsec_policy = IP_IPSEC_POLICY;
                        break;
                }
-               policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
-               if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+               case AF_INET6:
                {
-                       DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
-                                strerror(errno));
-                       status = FALSE;
+                       sol = SOL_IPV6;
+                       ipsec_policy = IPV6_IPSEC_POLICY;
                        break;
                }
+               default:
+                       return FALSE;
        }
-       sockets->destroy(sockets);
-       return status;
+
+       memset(&policy, 0, sizeof(policy));
+       policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
+       policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+       policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
+
+       policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
+       if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+       {
+               DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
+                        strerror(errno));
+               return FALSE;
+       }
+       policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+       if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+       {
+               DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
+                        strerror(errno));
+               return FALSE;
+       }
+       return TRUE;
+}
+
+METHOD(kernel_ipsec_t, destroy, void,
+       private_kernel_pfkey_ipsec_t *this)
+{
+       this->job->cancel(this->job);
+       close(this->socket);
+       close(this->socket_events);
+       this->policies->destroy_function(this->policies, (void*)policy_entry_destroy);
+       this->mutex->destroy(this->mutex);
+       this->mutex_pfkey->destroy(this->mutex_pfkey);
+       free(this);
 }
 
 /*
@@ -2133,6 +2120,7 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
                        .add_policy = _add_policy,
                        .query_policy = _query_policy,
                        .del_policy = _del_policy,
+                       .bypass_socket = _bypass_socket,
                        .destroy = _destroy,
                },
                .policies = linked_list_create(),
@@ -2156,12 +2144,6 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
                charon->kill(charon, "unable to create PF_KEY event socket");
        }
 
-       /* add bypass policies on the sockets used by charon */
-       if (!add_bypass_policies(this))
-       {
-               charon->kill(charon, "unable to add bypass policies on sockets");
-       }
-
        /* register the event socket */
        if (register_pfkey_socket(this, SADB_SATYPE_ESP) != SUCCESS ||
                register_pfkey_socket(this, SADB_SATYPE_AH) != SUCCESS)
index d69f309..bc99818 100644 (file)
@@ -521,6 +521,12 @@ static int open_socket(private_socket_default_socket_t *this,
                }
        }
 
+       if (!charon->kernel_interface->bypass_socket(charon->kernel_interface,
+                                                                                                skt, family))
+       {
+               DBG1(DBG_NET, "installing IKE bypass policy failed");
+       }
+
 #ifndef __APPLE__
        {
                /* enable UDP decapsulation globally, only for one socket needed */
@@ -535,66 +541,6 @@ static int open_socket(private_socket_default_socket_t *this,
        return skt;
 }
 
-/**
- * enumerator for underlying sockets
- */
-typedef struct {
-       /** implements enumerator_t */
-       enumerator_t public;
-       /** sockets we enumerate */
-       private_socket_default_socket_t *socket;
-       /** counter */
-       int index;
-} socket_enumerator_t;
-
-/**
- * enumerate function for socket_enumerator_t
- */
-static bool enumerate(socket_enumerator_t *this, int *fd, int *family, int *port)
-{
-       static const struct {
-               int fd_offset;
-               int family;
-               int port;
-       } sockets[] = {
-               { offsetof(private_socket_default_socket_t, ipv4),
-                       AF_INET, IKEV2_UDP_PORT },
-               { offsetof(private_socket_default_socket_t, ipv6),
-                       AF_INET6, IKEV2_UDP_PORT },
-               { offsetof(private_socket_default_socket_t, ipv4_natt),
-                       AF_INET, IKEV2_NATT_PORT },
-               { offsetof(private_socket_default_socket_t, ipv6_natt),
-                       AF_INET6, IKEV2_NATT_PORT }
-       };
-
-       while(++this->index < countof(sockets))
-       {
-               int sock = *(int*)((char*)this->socket + sockets[this->index].fd_offset);
-               if (!sock)
-               {
-                       continue;
-               }
-               *fd = sock;
-               *family = sockets[this->index].family;
-               *port = sockets[this->index].port;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-METHOD(socket_t, create_enumerator, enumerator_t*,
-       private_socket_default_socket_t *this)
-{
-       socket_enumerator_t *enumerator;
-
-       enumerator = malloc_thing(socket_enumerator_t);
-       enumerator->index = -1;
-       enumerator->socket = this;
-       enumerator->public.enumerate = (void*)enumerate;
-       enumerator->public.destroy = (void*)free;
-       return &enumerator->public;
-}
-
 METHOD(socket_default_socket_t, destroy, void,
        private_socket_default_socket_t *this)
 {
@@ -629,7 +575,6 @@ socket_default_socket_t *socket_default_socket_create()
                        .socket = {
                                .send = _sender,
                                .receive = _receiver,
-                               .create_enumerator = _create_enumerator,
                        },
                        .destroy = _destroy,
                },
index 7835856..e0155fa 100644 (file)
@@ -492,6 +492,12 @@ static int open_send_socket(private_socket_raw_socket_t *this,
                }
        }
 
+       if (!charon->kernel_interface->bypass_socket(charon->kernel_interface,
+                                                                                                skt, family))
+       {
+               DBG1(DBG_NET, "installing bypass policy on send socket failed");
+       }
+
        return skt;
 }
 
@@ -590,65 +596,13 @@ static int open_recv_socket(private_socket_raw_socket_t *this, int family)
                return 0;
        }
 
-       return skt;
-}
-
-/**
- * enumerator for underlying sockets
- */
-typedef struct {
-       /** implements enumerator_t */
-       enumerator_t public;
-       /** sockets we enumerate */
-       private_socket_raw_socket_t *socket;
-       /** counter */
-       int index;
-} socket_enumerator_t;
-
-/**
- * enumerate function for socket_enumerator_t
- */
-static bool enumerate(socket_enumerator_t *this, int *fd, int *family, int *port)
-{
-       static const struct {
-               int fd_offset;
-               int family;
-               int port;
-       } sockets[] = {
-               { offsetof(private_socket_raw_socket_t, recv4), AF_INET, IKEV2_UDP_PORT },
-               { offsetof(private_socket_raw_socket_t, recv6), AF_INET6, IKEV2_UDP_PORT },
-               { offsetof(private_socket_raw_socket_t, send4), AF_INET, IKEV2_UDP_PORT },
-               { offsetof(private_socket_raw_socket_t, send6), AF_INET6, IKEV2_UDP_PORT },
-               { offsetof(private_socket_raw_socket_t, send4_natt), AF_INET, IKEV2_NATT_PORT },
-               { offsetof(private_socket_raw_socket_t, send6_natt), AF_INET6, IKEV2_NATT_PORT }
-       };
-
-       while(++this->index < countof(sockets))
+       if (!charon->kernel_interface->bypass_socket(charon->kernel_interface,
+                                                                                                skt, family))
        {
-               int sock = *(int*)((char*)this->socket + sockets[this->index].fd_offset);
-               if (!sock)
-               {
-                       continue;
-               }
-               *fd = sock;
-               *family = sockets[this->index].family;
-               *port = sockets[this->index].port;
-               return TRUE;
+               DBG1(DBG_NET, "installing bypass policy on receive socket failed");
        }
-       return FALSE;
-}
 
-METHOD(socket_t, create_enumerator, enumerator_t*,
-       private_socket_raw_socket_t *this)
-{
-       socket_enumerator_t *enumerator;
-
-       enumerator = malloc_thing(socket_enumerator_t);
-       enumerator->index = -1;
-       enumerator->socket = this;
-       enumerator->public.enumerate = (void*)enumerate;
-       enumerator->public.destroy = (void*)free;
-       return &enumerator->public;
+       return skt;
 }
 
 METHOD(socket_raw_socket_t, destroy, void,
@@ -693,7 +647,6 @@ socket_raw_socket_t *socket_raw_socket_create()
                        .socket = {
                                .send = _sender,
                                .receive = _receiver,
-                               .create_enumerator = _create_enumerator,
                        },
                        .destroy = _destroy,
                },