]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-libipsec: Add support to send/receive raw ESP packets
authorTobias Brunner <tobias@strongswan.org>
Thu, 11 May 2023 16:34:58 +0000 (18:34 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 23 May 2023 11:19:47 +0000 (13:19 +0200)
This is currently only supported on Linux and with the appropriate
permissions.

Since it's experimental, it's disabled by default.

The log messages for each sent and received ESP message are logged in NET
like the ones in the socket-default plugin for UDP-encapsulated messages.

conf/plugins/kernel-libipsec.opt
src/libcharon/plugins/kernel_libipsec/Makefile.am
src/libcharon/plugins/kernel_libipsec/kernel_libipsec_esp_handler.c [new file with mode: 0644]
src/libcharon/plugins/kernel_libipsec/kernel_libipsec_esp_handler.h [new file with mode: 0644]
src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c
src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c

index e76db63d946c54863256d96547be865e47f32300..a79d00d1c7fb8dc50d481dbe461d918dbddb3210 100644 (file)
@@ -5,3 +5,10 @@ charon.plugins.kernel-libipsec.allow_peer_ts = no
        installed for such traffic (via TUN device) usually prevents further IKE
        traffic. The fwmark options for the _kernel-netlink_ and _socket-default_
        plugins can be used to circumvent that problem.
+
+charon.plugins.kernel-libipsec.fwmark = charon.plugins.socket-default.fwmark
+       Firewall mark to set on outbound raw ESP packets.
+
+charon.plugins.kernel-libipsec.raw_esp = no
+       Whether to send and receive ESP packets without UDP encapsulation if
+       supported on this platform and no NAT is detected.
index 4757280b4ebafd96d2a3a6eba4fe7731ae8c5ad3..604d6b4fb67ff303089158702e79667b7dfb6ed3 100644 (file)
@@ -15,7 +15,8 @@ endif
 libstrongswan_kernel_libipsec_la_SOURCES = \
        kernel_libipsec_plugin.h kernel_libipsec_plugin.c \
        kernel_libipsec_ipsec.h kernel_libipsec_ipsec.c \
-       kernel_libipsec_router.h kernel_libipsec_router.c
+       kernel_libipsec_router.h kernel_libipsec_router.c \
+       kernel_libipsec_esp_handler.h kernel_libipsec_esp_handler.c
 
 libstrongswan_kernel_libipsec_la_LIBADD = $(top_builddir)/src/libipsec/libipsec.la
 
diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_esp_handler.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_esp_handler.c
new file mode 100644 (file)
index 0000000..095ad67
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2023 Tobias Brunner
+ *
+ * Copyright (C) secunet Security Networks AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/* for struct in6_pktinfo */
+#define _GNU_SOURCE
+
+#include "kernel_libipsec_esp_handler.h"
+
+#ifdef __linux__
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <ipsec.h>
+#include <collections/blocking_queue.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_kernel_libipsec_esp_handler_t private_kernel_libipsec_esp_handler_t;
+
+/**
+ * Private data
+ */
+struct private_kernel_libipsec_esp_handler_t {
+
+       /**
+        * Public interface
+        */
+       kernel_libipsec_esp_handler_t public;
+
+       /**
+        * Queue for outbound ESP packets (esp_packet_t*)
+        */
+       blocking_queue_t *queue;
+
+       /**
+        * Socket to send/receive IPv4 ESP packets
+        */
+       int skt_v4;
+
+       /**
+        * Socket to send/receive IPv6 ESP packets
+        */
+       int skt_v6;
+};
+
+METHOD(kernel_libipsec_esp_handler_t, send_, void,
+       private_kernel_libipsec_esp_handler_t *this, esp_packet_t *packet)
+{
+       this->queue->enqueue(this->queue, packet);
+}
+
+CALLBACK(send_esp, job_requeue_t,
+       private_kernel_libipsec_esp_handler_t *this)
+{
+       packet_t *packet;
+       host_t *source, *destination;
+       chunk_t data;
+       struct msghdr msg = {};
+       struct cmsghdr *cmsg;
+       struct iovec iov;
+       char ancillary[64] = {};
+       ssize_t len;
+       int skt;
+
+       packet = (packet_t*)this->queue->dequeue(this->queue);
+
+       data = packet->get_data(packet);
+       source = packet->get_source(packet);
+       destination = packet->get_destination(packet);
+       DBG2(DBG_NET, "sending raw ESP packet: from %H to %H (%zu data bytes)",
+                source, destination, data.len);
+
+       /* the port of the destination address acts as protocol selector for RAW
+        * sockets, for IPv4 the kernel ignores it, for IPv6 it does not and
+        * complains if it isn't zero or doesn't match the one set on the socket */
+       destination->set_port(destination, 0);
+
+       msg.msg_name = destination->get_sockaddr(destination);
+       msg.msg_namelen = *destination->get_sockaddr_len(destination);
+       iov.iov_base = data.ptr;
+       iov.iov_len = data.len;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_flags = 0;
+       msg.msg_control = ancillary;
+
+       if (source->get_family(source) == AF_INET)
+       {
+               struct in_pktinfo *pktinfo;
+               const struct sockaddr_in *sin;
+
+               msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+               cmsg = CMSG_FIRSTHDR(&msg);
+               cmsg->cmsg_level = IPPROTO_IP;
+               cmsg->cmsg_type = IP_PKTINFO;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+               pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+               sin = (struct sockaddr_in*)source->get_sockaddr(source);
+               memcpy(&pktinfo->ipi_spec_dst, &sin->sin_addr, sizeof(struct in_addr));
+               skt = this->skt_v4;
+       }
+       else
+       {
+               struct in6_pktinfo *pktinfo;
+               const struct sockaddr_in6 *sin;
+
+               msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+               cmsg = CMSG_FIRSTHDR(&msg);
+               cmsg->cmsg_level = IPPROTO_IPV6;
+               cmsg->cmsg_type = IPV6_PKTINFO;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+
+               pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+               sin = (struct sockaddr_in6*)source->get_sockaddr(source);
+               memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
+               skt = this->skt_v6;
+       }
+
+       len = sendmsg(skt, &msg, 0);
+       if (len != data.len)
+       {
+               DBG1(DBG_KNL, "error writing to ESP socket: %s", strerror(errno));
+       }
+       packet->destroy(packet);
+       return JOB_REQUEUE_DIRECT;
+}
+
+CALLBACK(receive_esp, bool,
+       private_kernel_libipsec_esp_handler_t *this, int fd, watcher_event_t event)
+{
+       char buf[2048];
+       struct msghdr msg;
+       struct cmsghdr *cmsg;
+       struct iovec iov;
+       char ancillary[64];
+       union {
+               struct sockaddr_in in4;
+               struct sockaddr_in6 in6;
+       } src;
+       host_t *source, *destination = NULL;
+       packet_t *packet;
+       chunk_t data;
+       ssize_t len;
+
+       msg.msg_name = &src;
+       msg.msg_namelen = sizeof(src);
+       iov.iov_base = buf;
+       iov.iov_len = sizeof(buf);
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = ancillary;
+       msg.msg_controllen = sizeof(ancillary);
+       msg.msg_flags = 0;
+
+       len = recvmsg(fd, &msg, MSG_DONTWAIT|MSG_TRUNC);
+       if (len < 0)
+       {
+               if (errno != EAGAIN && errno != EWOULDBLOCK)
+               {
+                       DBG1(DBG_KNL, "receiving from ESP socket failed: %s",
+                                strerror(errno));
+               }
+               return TRUE;
+       }
+       else if (msg.msg_flags & MSG_TRUNC)
+       {
+               DBG1(DBG_KNL, "ESP packet with length %zd exceeds buffer size of %zu",
+                        len, sizeof(buf));
+               return TRUE;
+       }
+       data = chunk_create(buf, len);
+       /* skip the IP header returned by IPv4 raw sockets */
+       if (fd == this->skt_v4)
+       {
+               data = chunk_skip(data, sizeof(struct iphdr));
+       }
+
+       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
+       {
+               if (cmsg->cmsg_level == IPPROTO_IP &&
+                       cmsg->cmsg_type == IP_PKTINFO)
+               {
+                       const struct in_pktinfo *pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+                       struct sockaddr_in dst = {
+                               .sin_family = AF_INET,
+                       };
+
+                       memcpy(&dst.sin_addr, &pktinfo->ipi_addr, sizeof(dst.sin_addr));
+                       destination = host_create_from_sockaddr((sockaddr_t*)&dst);
+               }
+               else if (cmsg->cmsg_level == IPPROTO_IPV6 &&
+                                cmsg->cmsg_type == IPV6_PKTINFO)
+               {
+                       const struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+                       struct sockaddr_in6 dst = {
+                               .sin6_family = AF_INET6,
+                       };
+
+                       memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr));
+                       destination = host_create_from_sockaddr((sockaddr_t*)&dst);
+               }
+               if (destination)
+               {
+                       break;
+               }
+       }
+       if (!destination)
+       {
+               DBG1(DBG_KNL, "error reading destination IP address for ESP packet");
+               return TRUE;
+       }
+       source = host_create_from_sockaddr((sockaddr_t*)&src);
+       DBG2(DBG_NET, "received raw ESP packet: from %#H to %#H (%zu data bytes)",
+                source, destination, data.len);
+
+       packet = packet_create();
+       packet->set_source(packet, source);
+       packet->set_destination(packet, destination);
+       packet->set_data(packet, chunk_clone(data));
+       ipsec->processor->queue_inbound(ipsec->processor,
+                                                                       esp_packet_create_from_packet(packet));
+       return TRUE;
+}
+
+METHOD(kernel_libipsec_esp_handler_t, destroy, void,
+       private_kernel_libipsec_esp_handler_t *this)
+{
+       if (this->skt_v4 >= 0)
+       {
+               lib->watcher->remove(lib->watcher, this->skt_v4);
+               close(this->skt_v4);
+       }
+       if (this->skt_v6 >= 0)
+       {
+               lib->watcher->remove(lib->watcher, this->skt_v6);
+               close(this->skt_v6);
+       }
+       this->queue->destroy_offset(this->queue, offsetof(esp_packet_t, destroy));
+       free(this);
+}
+
+/**
+ * Create a RAW socket for the given address family
+ */
+static int create_socket(int family)
+{
+       const char *fwmark;
+       mark_t mark;
+       int skt, on = 1;
+
+       skt = socket(family, SOCK_RAW, IPPROTO_ESP);
+       if (skt == -1)
+       {
+               DBG1(DBG_KNL, "opening RAW socket for ESP failed: %s", strerror(errno));
+               return -1;
+       }
+       if (setsockopt(skt, family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6,
+                                  family == AF_INET ? IP_PKTINFO : IPV6_RECVPKTINFO,
+                                  &on, sizeof(on)) == -1)
+       {
+               DBG1(DBG_KNL, "unable to set PKTINFO on ESP socket: %s",
+                        strerror(errno));
+               close(skt);
+               return -1;
+       }
+       fwmark = lib->settings->get_str(lib->settings,
+                                       "%s.plugins.kernel-libipsec.fwmark",
+                                               lib->settings->get_str(lib->settings,
+                                                       "%s.plugins.socket-default.fwmark", NULL, lib->ns),
+                                       lib->ns);
+       if (fwmark && mark_from_string(fwmark, MARK_OP_NONE, &mark) &&
+               setsockopt(skt, SOL_SOCKET, SO_MARK, &mark.value, sizeof(mark.value)) < 0)
+       {
+               DBG1(DBG_KNL, "unable to set SO_MARK on ESP socket: %s",
+                        strerror(errno));
+       }
+       return skt;
+}
+
+/*
+ * Described in header
+ */
+kernel_libipsec_esp_handler_t *kernel_libipsec_esp_handler_create()
+{
+       private_kernel_libipsec_esp_handler_t *this;
+
+       if (!lib->caps->keep(lib->caps, CAP_NET_RAW))
+       {       /* required to open SOCK_RAW sockets and according to capabilities(7)
+                * it is also required to use the socket */
+               DBG1(DBG_KNL, "kernel-libipsec requires CAP_NET_RAW capability to send "
+                        "and receive ESP packets without UDP encapsulation");
+               return NULL;
+       }
+
+       INIT(this,
+               .public = {
+                       .send = _send_,
+                       .destroy = _destroy,
+               },
+               .queue = blocking_queue_create(),
+               .skt_v4 = create_socket(AF_INET),
+               .skt_v6 = create_socket(AF_INET6),
+       );
+
+       if (this->skt_v4 == -1 && this->skt_v6  == -1)
+       {
+               destroy(this);
+               return NULL;
+       }
+       if (this->skt_v4 >= 0)
+       {
+               lib->watcher->add(lib->watcher, this->skt_v4, WATCHER_READ,
+                                                 receive_esp, this);
+       }
+       if (this->skt_v6 >= 0)
+       {
+               lib->watcher->add(lib->watcher, this->skt_v6, WATCHER_READ,
+                                                 receive_esp, this);
+       }
+       lib->processor->queue_job(lib->processor,
+                       (job_t*)callback_job_create(send_esp, this, NULL,
+                                                                               (callback_job_cancel_t)return_false));
+       return &this->public;
+}
+
+#else /* __linux__ */
+
+kernel_libipsec_esp_handler_t *kernel_libipsec_esp_handler_create()
+{
+       return NULL;
+}
+
+#endif /* __linux__ */
diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_esp_handler.h b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_esp_handler.h
new file mode 100644 (file)
index 0000000..6b7a108
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 Tobias Brunner
+ *
+ * Copyright (C) secunet Security Networks AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup kernel_libipsec_esp_handler kernel_libipsec_esp_handler
+ * @{ @ingroup kernel_libipsec
+ */
+
+#ifndef KERNEL_LIBIPSEC_ESP_HANDLER_H_
+#define KERNEL_LIBIPSEC_ESP_HANDLER_H_
+
+#include <esp_packet.h>
+
+typedef struct kernel_libipsec_esp_handler_t kernel_libipsec_esp_handler_t;
+
+/**
+ * Class that sends and receives raw ESP packets.
+ */
+struct kernel_libipsec_esp_handler_t {
+
+       /**
+        * Send the given ESP packet without UDP encapsulation.
+        *
+        * @param packet        ESP packet to send
+        */
+       void (*send)(kernel_libipsec_esp_handler_t *this, esp_packet_t *packet);
+
+       /**
+        * Destroy the given instance.
+        */
+       void (*destroy)(kernel_libipsec_esp_handler_t *this);
+};
+
+/**
+ * Create a kernel_libipsec_esp_handler_t instance.
+ *
+ * @return                             created instance, NULL if not supported
+ */
+kernel_libipsec_esp_handler_t *kernel_libipsec_esp_handler_create();
+
+#endif /** KERNEL_LIBIPSEC_ESP_HANDLER_H_ @}*/
index 174751833542d5a72e3c3425fe0b32af8a8568c8..22e1200dd99019933a4fc295154fa3a650be943c 100644 (file)
@@ -56,6 +56,11 @@ struct private_kernel_libipsec_ipsec_t {
         * Whether the remote TS may equal the IKE peer
         */
        bool allow_peer_ts;
+
+       /**
+        * Whether UDP encapsulation is required
+        */
+       bool require_encap;
 };
 
 typedef struct exclude_route_t exclude_route_t;
@@ -241,8 +246,8 @@ static void acquire(uint32_t reqid)
 METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
        private_kernel_libipsec_ipsec_t *this)
 {
-       return KERNEL_REQUIRE_UDP_ENCAPSULATION | KERNEL_ESP_V3_TFC |
-                  KERNEL_SA_USE_TIME;
+       return KERNEL_ESP_V3_TFC | KERNEL_SA_USE_TIME |
+                       (this->require_encap ? KERNEL_REQUIRE_UDP_ENCAPSULATION : 0);
 }
 
 METHOD(kernel_ipsec_t, get_spi, status_t,
@@ -263,7 +268,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
        kernel_ipsec_add_sa_t *data)
 {
-       if (!data->encap)
+       if (this->require_encap && !data->encap)
        {
                DBG1(DBG_ESP, "failed to add SAD entry: only UDP encapsulation is "
                         "supported");
@@ -704,6 +709,7 @@ kernel_libipsec_ipsec_t *kernel_libipsec_ipsec_create()
                .excludes = linked_list_create(),
                .allow_peer_ts = lib->settings->get_bool(lib->settings,
                                        "%s.plugins.kernel-libipsec.allow_peer_ts", FALSE, lib->ns),
+               .require_encap = !lib->get(lib, "kernel-libipsec-esp-handler"),
        );
 
        ipsec->events->register_listener(ipsec->events, &this->ipsec_listener);
index 0b25518f4b5d9b0a734ebcfd6a340474709f709f..f539693eb55855572285c7b832b4070dd07f7005 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2013 Tobias Brunner
+ * Copyright (C) 2012-2023 Tobias Brunner
  *
  * Copyright (C) secunet Security Networks AG
  *
@@ -17,6 +17,7 @@
 #include "kernel_libipsec_plugin.h"
 #include "kernel_libipsec_ipsec.h"
 #include "kernel_libipsec_router.h"
+#include "kernel_libipsec_esp_handler.h"
 
 #include <daemon.h>
 #include <ipsec.h>
@@ -45,6 +46,11 @@ struct private_kernel_libipsec_plugin_t {
         * Packet router
         */
        kernel_libipsec_router_t *router;
+
+       /**
+        * Raw ESP handler
+        */
+       kernel_libipsec_esp_handler_t *esp_handler;
 };
 
 METHOD(plugin_t, get_name, char*,
@@ -92,6 +98,11 @@ METHOD(plugin_t, destroy, void,
                lib->set(lib, "kernel-libipsec-tun", NULL);
                this->tun->destroy(this->tun);
        }
+       if (this->esp_handler)
+       {
+               lib->set(lib, "kernel-libipsec-esp-handler", NULL);
+               this->esp_handler->destroy(this->esp_handler);
+       }
        libipsec_deinit();
        free(this);
 }
@@ -146,5 +157,17 @@ plugin_t *kernel_libipsec_plugin_create()
        /* set TUN device as default to install VIPs */
        lib->settings->set_str(lib->settings, "%s.install_virtual_ip_on",
                                                   this->tun->get_name(this->tun), lib->ns);
+
+       if (lib->settings->get_bool(lib->settings,
+                                               "%s.plugins.kernel-libipsec.raw_esp", FALSE, lib->ns))
+       {
+               this->esp_handler = kernel_libipsec_esp_handler_create();
+               if (!this->esp_handler)
+               {
+                       DBG1(DBG_KNL, "only UDP-encapsulated ESP packets supported by "
+                                "kernel-libipsec on this platform");
+               }
+               lib->set(lib, "kernel-libipsec-esp-handler", this->esp_handler);
+       }
        return &this->public.plugin;
 }
index 07a4da4a306649285318fea3502413c741b98f9d..74746e251de0302f422999f7ef2bb65487e977d1 100644 (file)
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 
 #include "kernel_libipsec_router.h"
+#include "kernel_libipsec_esp_handler.h"
 
 #include <daemon.h>
 #include <ipsec.h>
@@ -76,6 +77,11 @@ struct private_kernel_libipsec_router_t {
         * Pipe to signal handle_plain() about changes regarding TUN devices
         */
        int notify[2];
+
+       /**
+        * ESP handler to send raw ESP packets
+        */
+       kernel_libipsec_esp_handler_t *esp_handler;
 };
 
 /**
@@ -95,9 +101,20 @@ static bool tun_entry_equals(tun_entry_t *a, tun_entry_t *b)
 }
 
 CALLBACK(send_esp, void,
-       void *data, esp_packet_t *packet, bool encap)
+       private_kernel_libipsec_router_t *this, esp_packet_t *packet, bool encap)
 {
-       charon->sender->send_no_marker(charon->sender, (packet_t*)packet);
+       if (encap)
+       {
+               charon->sender->send_no_marker(charon->sender, (packet_t*)packet);
+       }
+       else if (this->esp_handler)
+       {
+               this->esp_handler->send(this->esp_handler, packet);
+       }
+       else
+       {       /* shouldn't happen as UDP encap is forced without ESP handler */
+               packet->destroy(packet);
+       }
 }
 
 CALLBACK(receiver_esp_cb, void,
@@ -323,7 +340,8 @@ kernel_libipsec_router_t *kernel_libipsec_router_create()
                },
                .tun = {
                        .tun = lib->get(lib, "kernel-libipsec-tun"),
-               }
+               },
+               .esp_handler = lib->get(lib, "kernel-libipsec-esp-handler"),
        );
 
        if (pipe(this->notify) != 0 ||
@@ -341,7 +359,7 @@ kernel_libipsec_router_t *kernel_libipsec_router_create()
        this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
 
        charon->kernel->add_listener(charon->kernel, &this->public.listener);
-       ipsec->processor->register_outbound(ipsec->processor, send_esp, NULL);
+       ipsec->processor->register_outbound(ipsec->processor, send_esp, this);
        ipsec->processor->register_inbound(ipsec->processor, deliver_plain, this);
        charon->receiver->add_esp_cb(charon->receiver, receiver_esp_cb, NULL);
        lib->processor->queue_job(lib->processor,