diff --git a/conf/plugins/kernel-libipsec.opt b/conf/plugins/kernel-libipsec.opt index e76db63d9..a79d00d1c 100644 --- a/conf/plugins/kernel-libipsec.opt +++ b/conf/plugins/kernel-libipsec.opt @@ -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. diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c index 179371c90..f7e6ec34b 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c @@ -85,19 +85,14 @@ struct private_android_service_t { bool use_dns_proxy; }; -/** - * Outbound callback - */ -static void send_esp(void *data, esp_packet_t *packet) +CALLBACK(send_esp, void, + void *data, esp_packet_t *packet, bool encap) { charon->sender->send_no_marker(charon->sender, (packet_t*)packet); } -/** - * Inbound callback - */ -static void deliver_plain(private_android_service_t *this, - ip_packet_t *packet) +CALLBACK(deliver_plain, void, + private_android_service_t *this, ip_packet_t *packet) { chunk_t encoding; ssize_t len; @@ -122,10 +117,8 @@ static void deliver_plain(private_android_service_t *this, packet->destroy(packet); } -/** - * Receiver callback - */ -static void receiver_esp_cb(void *data, packet_t *packet) +CALLBACK(receiver_esp_cb, void, + void *data, packet_t *packet) { esp_packet_t *esp_packet; @@ -359,14 +352,10 @@ static bool setup_tun_device(private_android_service_t *this, if (!already_registered) { - charon->receiver->add_esp_cb(charon->receiver, - (receiver_esp_cb_t)receiver_esp_cb, NULL); - ipsec->processor->register_inbound(ipsec->processor, - (ipsec_inbound_cb_t)deliver_plain, this); - ipsec->processor->register_outbound(ipsec->processor, - (ipsec_outbound_cb_t)send_esp, NULL); - this->dns_proxy->register_cb(this->dns_proxy, - (dns_proxy_response_cb_t)deliver_plain, this); + charon->receiver->add_esp_cb(charon->receiver, receiver_esp_cb, NULL); + ipsec->processor->register_inbound(ipsec->processor, deliver_plain, this); + ipsec->processor->register_outbound(ipsec->processor, send_esp, NULL); + this->dns_proxy->register_cb(this->dns_proxy, deliver_plain, this); lib->processor->queue_job(lib->processor, (job_t*)callback_job_create((callback_job_cb_t)handle_plain, this, @@ -422,14 +411,10 @@ static void close_tun_device(private_android_service_t *this) this->tunfd = -1; this->lock->unlock(this->lock); - this->dns_proxy->unregister_cb(this->dns_proxy, - (dns_proxy_response_cb_t)deliver_plain); - ipsec->processor->unregister_outbound(ipsec->processor, - (ipsec_outbound_cb_t)send_esp); - ipsec->processor->unregister_inbound(ipsec->processor, - (ipsec_inbound_cb_t)deliver_plain); - charon->receiver->del_esp_cb(charon->receiver, - (receiver_esp_cb_t)receiver_esp_cb); + this->dns_proxy->unregister_cb(this->dns_proxy, deliver_plain); + ipsec->processor->unregister_outbound(ipsec->processor, send_esp); + ipsec->processor->unregister_inbound(ipsec->processor, deliver_plain); + charon->receiver->del_esp_cb(charon->receiver, receiver_esp_cb); close(tunfd); } diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_ipsec.c b/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_ipsec.c index 7af027e75..b2caed97c 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_ipsec.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_ipsec.c @@ -71,6 +71,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t, private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id, kernel_ipsec_add_sa_t *data) { + if (!data->encap) + { + DBG1(DBG_ESP, "failed to add SAD entry: only UDP encapsulation is " + "supported"); + return FAILED; + } return ipsec->sas->add_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto, data->reqid, id->mark, data->tfc, data->lifetime, data->enc_alg, data->enc_key, data->int_alg, data->int_key, @@ -82,6 +88,12 @@ METHOD(kernel_ipsec_t, update_sa, status_t, private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id, kernel_ipsec_update_sa_t *data) { + if (!data->new_encap) + { + DBG1(DBG_ESP, "failed to update SAD entry: can't deactivate UDP " + "encapsulation"); + return NOT_SUPPORTED; + } return ipsec->sas->update_sa(ipsec->sas, id->spi, id->proto, data->cpi, id->src, id->dst, data->new_src, data->new_dst, data->encap, data->new_encap, id->mark); diff --git a/src/libcharon/plugins/kernel_libipsec/Makefile.am b/src/libcharon/plugins/kernel_libipsec/Makefile.am index 4757280b4..604d6b4fb 100644 --- a/src/libcharon/plugins/kernel_libipsec/Makefile.am +++ b/src/libcharon/plugins/kernel_libipsec/Makefile.am @@ -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 index 000000000..095ad67b4 --- /dev/null +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_esp_handler.c @@ -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 . + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +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 index 000000000..6b7a1082c --- /dev/null +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_esp_handler.h @@ -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 . + * + * 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 + +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_ @}*/ diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c index 8df2e3dbc..22e1200dd 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c @@ -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,6 +268,12 @@ 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 (this->require_encap && !data->encap) + { + DBG1(DBG_ESP, "failed to add SAD entry: only UDP encapsulation is " + "supported"); + return FAILED; + } return ipsec->sas->add_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto, data->reqid, id->mark, data->tfc, data->lifetime, data->enc_alg, data->enc_key, data->int_alg, data->int_key, @@ -698,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); diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c index 0b25518f4..f539693eb 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c @@ -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 #include @@ -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; } diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c index 884616345..74746e251 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c @@ -18,6 +18,7 @@ #include #include "kernel_libipsec_router.h" +#include "kernel_libipsec_esp_handler.h" #include #include @@ -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; }; /** @@ -94,28 +100,32 @@ static bool tun_entry_equals(tun_entry_t *a, tun_entry_t *b) return a->addr->ip_equals(a->addr, b->addr); } -/** - * Outbound callback - */ -static void send_esp(void *data, esp_packet_t *packet) +CALLBACK(send_esp, void, + 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); + } } -/** - * Receiver callback - */ -static void receiver_esp_cb(void *data, packet_t *packet) +CALLBACK(receiver_esp_cb, void, + void *data, packet_t *packet) { ipsec->processor->queue_inbound(ipsec->processor, esp_packet_create_from_packet(packet)); } -/** - * Inbound callback - */ -static void deliver_plain(private_kernel_libipsec_router_t *this, - ip_packet_t *packet) +CALLBACK(deliver_plain, void, + private_kernel_libipsec_router_t *this, ip_packet_t *packet) { tun_device_t *tun; tun_entry_t *entry, lookup = { @@ -292,12 +302,9 @@ METHOD(kernel_libipsec_router_t, get_tun_name, char*, METHOD(kernel_libipsec_router_t, destroy, void, private_kernel_libipsec_router_t *this) { - charon->receiver->del_esp_cb(charon->receiver, - (receiver_esp_cb_t)receiver_esp_cb); - ipsec->processor->unregister_outbound(ipsec->processor, - (ipsec_outbound_cb_t)send_esp); - ipsec->processor->unregister_inbound(ipsec->processor, - (ipsec_inbound_cb_t)deliver_plain); + charon->receiver->del_esp_cb(charon->receiver, receiver_esp_cb); + ipsec->processor->unregister_outbound(ipsec->processor, send_esp); + ipsec->processor->unregister_inbound(ipsec->processor, deliver_plain); charon->kernel->remove_listener(charon->kernel, &this->public.listener); this->lock->destroy(this->lock); this->tuns->destroy(this->tuns); @@ -333,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 || @@ -351,11 +359,9 @@ 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_inbound(ipsec->processor, - (ipsec_inbound_cb_t)deliver_plain, this); - charon->receiver->add_esp_cb(charon->receiver, - (receiver_esp_cb_t)receiver_esp_cb, 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, (job_t*)callback_job_create((callback_job_cb_t)handle_plain, this, NULL, (callback_job_cancel_t)return_false)); diff --git a/src/libipsec/ipsec_processor.c b/src/libipsec/ipsec_processor.c index 11c587c93..2572b0880 100644 --- a/src/libipsec/ipsec_processor.c +++ b/src/libipsec/ipsec_processor.c @@ -169,12 +169,12 @@ static job_requeue_t process_inbound(private_ipsec_processor_t *this) * Send an ESP packet using the registered outbound callback */ static void send_outbound(private_ipsec_processor_t *this, - esp_packet_t *packet) + esp_packet_t *packet, bool encap) { this->lock->read_lock(this->lock); if (this->outbound.cb) { - this->outbound.cb(this->outbound.data, packet); + this->outbound.cb(this->outbound.data, packet, encap); } else { @@ -194,7 +194,7 @@ static job_requeue_t process_outbound(private_ipsec_processor_t *this) ip_packet_t *packet; ipsec_sa_t *sa; host_t *src, *dst; - bool acquire = FALSE; + bool acquire = FALSE, encap = FALSE; packet = (ip_packet_t*)this->outbound_queue->dequeue(this->outbound_queue); @@ -242,9 +242,10 @@ static job_requeue_t process_outbound(private_ipsec_processor_t *this) return JOB_REQUEUE_DIRECT; } sa->update_usestats(sa, packet->get_encoding(packet).len); + encap = sa->get_encap(sa); ipsec->sas->checkin(ipsec->sas, sa); policy->destroy(policy); - send_outbound(this, esp_packet); + send_outbound(this, esp_packet, encap); return JOB_REQUEUE_DIRECT; } diff --git a/src/libipsec/ipsec_processor.h b/src/libipsec/ipsec_processor.h index 734e8f53e..bc9d1863f 100644 --- a/src/libipsec/ipsec_processor.h +++ b/src/libipsec/ipsec_processor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2023 Tobias Brunner * * Copyright (C) secunet Security Networks AG * @@ -43,8 +43,10 @@ typedef void (*ipsec_inbound_cb_t)(void *data, ip_packet_t *packet); * * @param data data supplied during registration of the callback * @param packet ESP packet to send + * @param encap TRUE to send the packet with UDP encapsulation */ -typedef void (*ipsec_outbound_cb_t)(void *data, esp_packet_t *packet); +typedef void (*ipsec_outbound_cb_t)(void *data, esp_packet_t *packet, + bool encap); /** * IPsec processor diff --git a/src/libipsec/ipsec_sa.c b/src/libipsec/ipsec_sa.c index cfbaaff40..e67444bcb 100644 --- a/src/libipsec/ipsec_sa.c +++ b/src/libipsec/ipsec_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2023 Tobias Brunner * Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Ralf Sager * @@ -69,6 +69,11 @@ struct private_ipsec_sa_t { */ ipsec_mode_t mode; + /** + * TRUE if UDP encapsulation should be used when sending + */ + bool encap; + /** * TRUE if extended sequence numbers are used */ @@ -133,6 +138,18 @@ METHOD(ipsec_sa_t, set_destination, void, this->dst = addr->clone(addr); } +METHOD(ipsec_sa_t, get_encap, bool, + private_ipsec_sa_t *this) +{ + return this->encap; +} + +METHOD(ipsec_sa_t, set_encap, void, + private_ipsec_sa_t *this, bool encap) +{ + this->encap = encap; +} + METHOD(ipsec_sa_t, get_spi, uint32_t, private_ipsec_sa_t *this) { @@ -285,11 +302,6 @@ ipsec_sa_t *ipsec_sa_create(uint32_t spi, host_t *src, host_t *dst, DBG1(DBG_ESP, " IPsec SA: protocol not supported"); return NULL; } - if (!encap) - { - DBG1(DBG_ESP, " IPsec SA: only UDP encapsulation is supported"); - return NULL; - } if (esn) { DBG1(DBG_ESP, " IPsec SA: ESN not supported"); @@ -313,6 +325,8 @@ ipsec_sa_t *ipsec_sa_create(uint32_t spi, host_t *src, host_t *dst, .get_destination = _get_destination, .set_source = _set_source, .set_destination = _set_destination, + .get_encap = _get_encap, + .set_encap = _set_encap, .get_spi = _get_spi, .get_reqid = _get_reqid, .get_protocol = _get_protocol, @@ -333,6 +347,7 @@ ipsec_sa_t *ipsec_sa_create(uint32_t spi, host_t *src, host_t *dst, .protocol = protocol, .reqid = reqid, .mode = mode, + .encap = encap, .esn = esn, .inbound = inbound, ); diff --git a/src/libipsec/ipsec_sa.h b/src/libipsec/ipsec_sa.h index bc2c3a0cf..64c584b49 100644 --- a/src/libipsec/ipsec_sa.h +++ b/src/libipsec/ipsec_sa.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2023 Tobias Brunner * Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Ralf Sager * @@ -66,6 +66,20 @@ struct ipsec_sa_t { */ void (*set_destination)(ipsec_sa_t *this, host_t *addr); + /** + * Get whether UDP encapsulation should be used for this SA + * + * @return TRUE if encapsulation should be used, FALSE otherwise + */ + bool (*get_encap)(ipsec_sa_t *this); + + /** + * Set whether UDP encapsulation should be used for this SA + * + * @param encap TRUE if encapsulation should be used, FALSE otherwise + */ + void (*set_encap)(ipsec_sa_t *this, bool encap); + /** * Get the SPI for this SA * diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c index 12f5fc141..56698f3f0 100644 --- a/src/libipsec/ipsec_sa_mgr.c +++ b/src/libipsec/ipsec_sa_mgr.c @@ -502,7 +502,7 @@ METHOD(ipsec_sa_mgr_t, get_spi, status_t, METHOD(ipsec_sa_mgr_t, add_sa, status_t, private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint32_t spi, - uint8_t protocol, uint32_t reqid, mark_t mark, uint32_t tfc, + uint8_t protocol, uint32_t reqid, mark_t mark, uint32_t tfc, lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, uint16_t ipcomp, uint16_t cpi, bool initiator, bool encap, bool esn, bool inbound, @@ -568,13 +568,6 @@ METHOD(ipsec_sa_mgr_t, update_sa, status_t, DBG2(DBG_ESP, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", ntohl(spi), src, dst, new_src, new_dst); - if (!new_encap) - { - DBG1(DBG_ESP, "failed to update SAD entry: can't deactivate UDP " - "encapsulation"); - return NOT_SUPPORTED; - } - this->mutex->lock(this->mutex); if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb, (void**)&entry, spi, src, dst) && @@ -582,6 +575,7 @@ METHOD(ipsec_sa_mgr_t, update_sa, status_t, { entry->sa->set_source(entry->sa, new_src); entry->sa->set_destination(entry->sa, new_dst); + entry->sa->set_encap(entry->sa, new_encap); /* checkin the entry */ entry->locked = FALSE; entry->condvar->signal(entry->condvar); diff --git a/testing/tests/libipsec/host2host-cert-raw/description.txt b/testing/tests/libipsec/host2host-cert-raw/description.txt new file mode 100644 index 000000000..3c2ee919a --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/description.txt @@ -0,0 +1,11 @@ +A connection between the hosts moon and sun is set up. +The authentication is based on X.509 certificates and the kernel-libipsec +plugin is used for userland IPsec ESP encryption. In this scenario, UDP encapsulation +isn't enforced by the plugin as sending of raw ESP packets is enabled. +Firewall marks are used to make the direct ESP connection possible and +still allow IKE traffic to flow freely between the two hosts. +

+Upon the successful establishment of the IPsec tunnel, an updown script automatically +inserts iptables-based firewall rules that let pass the traffic tunneled via the +ipsec0 tun interface. In order to test both host-to-host tunnel and firewall, +moon pings sun. diff --git a/testing/tests/libipsec/host2host-cert-raw/evaltest.dat b/testing/tests/libipsec/host2host-cert-raw/evaltest.dat new file mode 100644 index 000000000..6bcf6e9a3 --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/evaltest.dat @@ -0,0 +1,5 @@ +moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_.eq=1::YES +moon::swanctl --list-sas --raw 2> /dev/null::host-host.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=500 local-id=moon.strongswan.org remote-host=192.168.0.2 remote-port=500 remote-id=sun.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*host-host.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128.*local-ts=\[192.168.0.1/32] remote-ts=\[192.168.0.2/32]::YES +sun::swanctl --list-sas --raw 2> /dev/null::host-host.*version=2 state=ESTABLISHED local-host=192.168.0.2 local-port=500 local-id=sun.strongswan.org remote-host=192.168.0.1 remote-port=500 remote-id=moon.strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*host-host.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128.*local-ts=\[192.168.0.2/32] remote-ts=\[192.168.0.1/32]::YES +sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES +sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES diff --git a/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/strongswan.conf b/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..ac1b85564 --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/strongswan.conf @@ -0,0 +1,24 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon-systemd { + load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac kdf vici kernel-libipsec kernel-netlink socket-default updown + + multiple_authentication = no + + plugins { + kernel-netlink { + fwmark = !0x42 + } + socket-default { + fwmark = 0x42 + } + kernel-libipsec { + allow_peer_ts = yes + raw_esp = yes + } + } +} diff --git a/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..f5553c0af --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/swanctl/swanctl.conf @@ -0,0 +1,26 @@ +connections { + + host-host { + local_addrs = 192.168.0.1 + remote_addrs = 192.168.0.2 + + local { + auth = pubkey + certs = moonCert.pem + id = moon.strongswan.org + } + remote { + auth = pubkey + id = sun.strongswan.org + } + children { + host-host { + updown = /etc/updown + esp_proposals = aes128-sha256-x25519 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-x25519 + } +} diff --git a/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/updown b/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/updown new file mode 100755 index 000000000..c56509b61 --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/hosts/moon/etc/updown @@ -0,0 +1,59 @@ +#!/bin/sh + +TUN_NAME=ipsec0 + +# use protocol specific options to set ports +case "$PLUTO_MY_PROTOCOL" in +1) # ICMP + ICMP_TYPE_OPTION="--icmp-type" + ;; +58) # ICMPv6 + ICMP_TYPE_OPTION="--icmpv6-type" + ;; +*) + ;; +esac + +# are there port numbers? +if [ "$PLUTO_MY_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + S_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + D_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + else + S_MY_PORT="--sport $PLUTO_MY_PORT" + D_MY_PORT="--dport $PLUTO_MY_PORT" + fi +fi +if [ "$PLUTO_PEER_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + # the syntax is --icmp[v6]-type type[/code], so add it to the existing option + S_MY_PORT="$S_MY_PORT/$PLUTO_PEER_PORT" + D_MY_PORT="$D_MY_PORT/$PLUTO_PEER_PORT" + else + S_PEER_PORT="--sport $PLUTO_PEER_PORT" + D_PEER_PORT="--dport $PLUTO_PEER_PORT" + fi +fi + +case "$PLUTO_VERB" in +up-host) + iptables -I OUTPUT 1 -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + iptables -I INPUT 1 -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +down-host) + iptables -D OUTPUT -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + iptables -D INPUT -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +esac diff --git a/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/strongswan.conf b/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/strongswan.conf new file mode 100644 index 000000000..ac1b85564 --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/strongswan.conf @@ -0,0 +1,24 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon-systemd { + load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac kdf vici kernel-libipsec kernel-netlink socket-default updown + + multiple_authentication = no + + plugins { + kernel-netlink { + fwmark = !0x42 + } + socket-default { + fwmark = 0x42 + } + kernel-libipsec { + allow_peer_ts = yes + raw_esp = yes + } + } +} diff --git a/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/swanctl/swanctl.conf b/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..cf11e7547 --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/swanctl/swanctl.conf @@ -0,0 +1,26 @@ +connections { + + host-host { + local_addrs = 192.168.0.2 + remote_addrs = 192.168.0.1 + + local { + auth = pubkey + certs = sunCert.pem + id = sun.strongswan.org + } + remote { + auth = pubkey + id = moon.strongswan.org + } + children { + host-host { + updown = /etc/updown + esp_proposals = aes128-sha256-x25519 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-x25519 + } +} diff --git a/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/updown b/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/updown new file mode 100755 index 000000000..c56509b61 --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/hosts/sun/etc/updown @@ -0,0 +1,59 @@ +#!/bin/sh + +TUN_NAME=ipsec0 + +# use protocol specific options to set ports +case "$PLUTO_MY_PROTOCOL" in +1) # ICMP + ICMP_TYPE_OPTION="--icmp-type" + ;; +58) # ICMPv6 + ICMP_TYPE_OPTION="--icmpv6-type" + ;; +*) + ;; +esac + +# are there port numbers? +if [ "$PLUTO_MY_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + S_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + D_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + else + S_MY_PORT="--sport $PLUTO_MY_PORT" + D_MY_PORT="--dport $PLUTO_MY_PORT" + fi +fi +if [ "$PLUTO_PEER_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + # the syntax is --icmp[v6]-type type[/code], so add it to the existing option + S_MY_PORT="$S_MY_PORT/$PLUTO_PEER_PORT" + D_MY_PORT="$D_MY_PORT/$PLUTO_PEER_PORT" + else + S_PEER_PORT="--sport $PLUTO_PEER_PORT" + D_PEER_PORT="--dport $PLUTO_PEER_PORT" + fi +fi + +case "$PLUTO_VERB" in +up-host) + iptables -I OUTPUT 1 -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + iptables -I INPUT 1 -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +down-host) + iptables -D OUTPUT -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + iptables -D INPUT -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +esac diff --git a/testing/tests/libipsec/host2host-cert-raw/posttest.dat b/testing/tests/libipsec/host2host-cert-raw/posttest.dat new file mode 100644 index 000000000..557ee303d --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/posttest.dat @@ -0,0 +1,7 @@ +moon::swanctl --terminate --ike host-host 2> /dev/null +moon::systemctl stop strongswan +sun::systemctl stop strongswan +moon::iptables-restore < /etc/iptables.flush +sun::iptables-restore < /etc/iptables.flush +moon::sysctl --pattern net.ipv4.conf.all.rp_filter --system +sun::sysctl --pattern net.ipv4.conf.all.rp_filter --system diff --git a/testing/tests/libipsec/host2host-cert-raw/pretest.dat b/testing/tests/libipsec/host2host-cert-raw/pretest.dat new file mode 100644 index 000000000..624728eac --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/pretest.dat @@ -0,0 +1,9 @@ +moon::sysctl -w net.ipv4.conf.all.rp_filter=2 +sun::sysctl -w net.ipv4.conf.all.rp_filter=2 +moon::iptables-restore < /etc/iptables.rules +sun::iptables-restore < /etc/iptables.rules +moon::systemctl start strongswan +sun::systemctl start strongswan +sun::expect-connection host-host +moon::expect-connection host-host +moon::swanctl --initiate --child host-host 2> /dev/null diff --git a/testing/tests/libipsec/host2host-cert-raw/test.conf b/testing/tests/libipsec/host2host-cert-raw/test.conf new file mode 100644 index 000000000..52d886dcc --- /dev/null +++ b/testing/tests/libipsec/host2host-cert-raw/test.conf @@ -0,0 +1,25 @@ +#!/bin/bash +# +# This configuration file provides information on the +# guest instances used for this test + +# All guest instances that are required for this test +# +VIRTHOSTS="moon winnetou sun" + +# Corresponding block diagram +# +DIAGRAM="m-w-s.png" + +# Guest instances on which tcpdump is to be started +# +TCPDUMPHOSTS="sun" + +# Guest instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon sun" + +# charon controlled by swanctl +# +SWANCTL=1 diff --git a/testing/tests/libipsec/net2net-cert-ipv6/description.txt b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/description.txt similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/description.txt rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/description.txt diff --git a/testing/tests/libipsec/net2net-cert-ipv6/evaltest.dat b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/evaltest.dat similarity index 85% rename from testing/tests/libipsec/net2net-cert-ipv6/evaltest.dat rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/evaltest.dat index cdb8ead3c..b92e71683 100644 --- a/testing/tests/libipsec/net2net-cert-ipv6/evaltest.dat +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/evaltest.dat @@ -1,5 +1,5 @@ alice::ping6 -c 3 -W 1 -i 0.2 -s 8184 -p deadbeef ip6-bob.strongswan.org::8192 bytes from ip6-bob.strongswan.org.*: icmp_seq=3::YES -moon ::swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.2 remote-port=4500 remote-id=sun.strongswan.org initiator=yes.*nat-remote=yes nat-any=yes encr-alg=AES_CBC encr-keysize=256 integ-alg=HMAC_SHA2_384_192 prf-alg=PRF_HMAC_SHA2_384 dh-group=ECP_384.*child-sas.*net-net.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP encap=yes.*encr-alg=AES_GCM_16 encr-keysize=256.*local-ts=\[fec1::/16\[ipv6-icmp]] remote-ts=\[fec2::/16\[ipv6-icmp]]::YES -sun ::swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=192.168.0.2 local-port=4500 local-id=sun.strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org.*nat-remote=yes nat-any=yes encr-alg=AES_CBC encr-keysize=256 integ-alg=HMAC_SHA2_384_192 prf-alg=PRF_HMAC_SHA2_384 dh-group=ECP_384.*child-sas.*net-net.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP encap=yes.*encr-alg=AES_GCM_16 encr-keysize=256.*local-ts=\[fec2::/16\[ipv6-icmp]] remote-ts=\[fec1::/16\[ipv6-icmp]]::YES +moon ::swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.2 remote-port=4500 remote-id=sun.strongswan.org initiator=yes.*nat-remote=yes nat-any=yes encr-alg=AES_CBC encr-keysize=256 integ-alg=HMAC_SHA2_384_192 prf-alg=PRF_HMAC_SHA2_384 dh-group=ECP_384.*child-sas.*net-net.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP encap=yes.*encr-alg=AES_GCM_16 encr-keysize=256.*local-ts=\[fec1:\:/16\[ipv6-icmp]] remote-ts=\[fec2:\:/16\[ipv6-icmp]]::YES +sun ::swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=192.168.0.2 local-port=4500 local-id=sun.strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org.*nat-remote=yes nat-any=yes encr-alg=AES_CBC encr-keysize=256 integ-alg=HMAC_SHA2_384_192 prf-alg=PRF_HMAC_SHA2_384 dh-group=ECP_384.*child-sas.*net-net.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP encap=yes.*encr-alg=AES_GCM_16 encr-keysize=256.*local-ts=\[fec2:\:/16\[ipv6-icmp]] remote-ts=\[fec1:\:/16\[ipv6-icmp]]::YES sun::tcpdump::IP moon.strongswan.org.\(4500\|ipsec-nat-t\) > sun.strongswan.org.\(4500\|ipsec-nat-t\): UDP-encap: ESP::YES sun::tcpdump::IP sun.strongswan.org.\(4500\|ipsec-nat-t\) > moon.strongswan.org.\(4500\|ipsec-nat-t\): UDP-encap: ESP::YES diff --git a/testing/tests/libipsec/net2net-cert-ipv6/hosts/moon/etc/strongswan.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/moon/etc/strongswan.conf similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/hosts/moon/etc/strongswan.conf rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/moon/etc/strongswan.conf diff --git a/testing/tests/libipsec/net2net-cert-ipv6/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/moon/etc/swanctl/swanctl.conf similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/hosts/moon/etc/swanctl/swanctl.conf rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/moon/etc/swanctl/swanctl.conf diff --git a/testing/tests/libipsec/net2net-cert-ipv6/hosts/moon/etc/updown b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/moon/etc/updown similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/hosts/moon/etc/updown rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/moon/etc/updown diff --git a/testing/tests/libipsec/net2net-cert-ipv6/hosts/sun/etc/strongswan.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/sun/etc/strongswan.conf similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/hosts/sun/etc/strongswan.conf rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/sun/etc/strongswan.conf diff --git a/testing/tests/libipsec/net2net-cert-ipv6/hosts/sun/etc/swanctl/swanctl.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/sun/etc/swanctl/swanctl.conf similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/hosts/sun/etc/swanctl/swanctl.conf rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/sun/etc/swanctl/swanctl.conf diff --git a/testing/tests/libipsec/net2net-cert-ipv6/hosts/sun/etc/updown b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/sun/etc/updown similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/hosts/sun/etc/updown rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/hosts/sun/etc/updown diff --git a/testing/tests/libipsec/net2net-cert-ipv6/posttest.dat b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/posttest.dat similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/posttest.dat rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/posttest.dat diff --git a/testing/tests/libipsec/net2net-cert-ipv6/pretest.dat b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/pretest.dat similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/pretest.dat rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/pretest.dat diff --git a/testing/tests/libipsec/net2net-cert-ipv6/test.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip4/test.conf similarity index 100% rename from testing/tests/libipsec/net2net-cert-ipv6/test.conf rename to testing/tests/libipsec/net2net-cert-ip6-in-ip4/test.conf diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/description.txt b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/description.txt new file mode 100644 index 000000000..1461b5e56 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/description.txt @@ -0,0 +1,11 @@ +An IPv6 ESP tunnel connection between the gateways moon and sun is set up. +It connects the two IPv6 subnets hiding behind their respective gateways. +The authentication is based on X.509 certificates and the kernel-libipsec +plugin is used for userland IPsec ESP encryption. In this scenario, UDP encapsulation +isn't enforced by the plugin as sending of raw ESP packets is enabled. +

+Upon the successful establishment of the IPsec tunnel, an updown script automatically +inserts iptables-based firewall rules that let pass the traffic tunneled via the +ipsec0 tun interface. In order to test both tunnel and firewall, client alice +behind gateway moon sends an IPv6 ICMP request to client bob behind sun +using the ping6 command. diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/evaltest.dat b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/evaltest.dat new file mode 100644 index 000000000..34e90c759 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/evaltest.dat @@ -0,0 +1,5 @@ +alice::ping6 -c 1 -p deadbeef ip6-bob.strongswan.org::64 bytes from ip6-bob.strongswan.org.*: icmp_seq=1::YES +moon::swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=fec0:\:1 local-port=500 local-id=moon.strongswan.org remote-host=fec0:\:2 remote-port=500 remote-id=sun.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*net-net.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[fec1:\:/16] remote-ts=\[fec2:\:/16]::YES +sun ::swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=fec0:\:2 local-port=500 local-id=sun.strongswan.org remote-host=fec0:\:1 remote-port=500 remote-id=moon.strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*net-net.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[fec2:\:/16] remote-ts=\[fec1:\:/16]::YES +sun::tcpdump::IP6 ip6-moon.strongswan.org > ip6-sun.strongswan.org: ESP::YES +sun::tcpdump::IP6 ip6-sun.strongswan.org > ip6-moon.strongswan.org: ESP::YES diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/strongswan.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..e2c90b0bf --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/strongswan.conf @@ -0,0 +1,15 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon-systemd { + load = random nonce aes sha1 sha2 gcm pem pkcs1 curve25519 gmp x509 curl revocation hmac kdf vici kernel-libipsec kernel-netlink socket-default updown + multiple_authentication = no + plugins { + kernel-libipsec { + raw_esp = yes + } + } +} diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..070310c18 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/swanctl/swanctl.conf @@ -0,0 +1,36 @@ +connections { + + gw-gw { + local_addrs = fec0::1 + remote_addrs = fec0::2 + + local { + auth = pubkey + certs = moonCert.pem + id = moon.strongswan.org + } + remote { + auth = pubkey + id = sun.strongswan.org + } + children { + net-net { + local_ts = fec1::0/16 + remote_ts = fec2::0/16 + + updown = /etc/updown + esp_proposals = aes128gcm128-x25519 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-x25519 + } +} + +authorities { + strongswan { + cacert = strongswanCert.pem + crl_uris = http://ip6-winnetou.strongswan.org/strongswan.crl + } +} \ No newline at end of file diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/updown b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/updown new file mode 100755 index 000000000..40b8fd303 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/moon/etc/updown @@ -0,0 +1,59 @@ +#!/bin/sh + +TUN_NAME=ipsec0 + +# use protocol specific options to set ports +case "$PLUTO_MY_PROTOCOL" in +1) # ICMP + ICMP_TYPE_OPTION="--icmp-type" + ;; +58) # ICMPv6 + ICMP_TYPE_OPTION="--icmpv6-type" + ;; +*) + ;; +esac + +# are there port numbers? +if [ "$PLUTO_MY_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + S_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + D_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + else + S_MY_PORT="--sport $PLUTO_MY_PORT" + D_MY_PORT="--dport $PLUTO_MY_PORT" + fi +fi +if [ "$PLUTO_PEER_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + # the syntax is --icmp[v6]-type type[/code], so add it to the existing option + S_MY_PORT="$S_MY_PORT/$PLUTO_PEER_PORT" + D_MY_PORT="$D_MY_PORT/$PLUTO_PEER_PORT" + else + S_PEER_PORT="--sport $PLUTO_PEER_PORT" + D_PEER_PORT="--dport $PLUTO_PEER_PORT" + fi +fi + +case "$PLUTO_VERB" in +up-client-v6) + ip6tables -I FORWARD 1 -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + ip6tables -I FORWARD 1 -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +down-client-v6) + ip6tables -D FORWARD -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + ip6tables -D FORWARD -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +esac diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/strongswan.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/strongswan.conf new file mode 100644 index 000000000..fa2a2a49c --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/strongswan.conf @@ -0,0 +1,15 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon-systemd { + load = random nonce aes sha1 sha2 gcm pem pkcs1 curve25519 gmp x509 curl revocation hmac kdf vici ker_nel-libipsec kernel-netlink socket-default updown + multiple_authentication = no + plugins { + kernel-libipsec { + raw_esp = yes + } + } +} diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/swanctl/swanctl.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..6d3bb7226 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/swanctl/swanctl.conf @@ -0,0 +1,37 @@ +connections { + + gw-gw { + local_addrs = fec0::2 + remote_addrs = fec0::1 + + local { + auth = pubkey + certs = sunCert.pem + id = sun.strongswan.org + } + remote { + auth = pubkey + id = moon.strongswan.org + } + children { + net-net { + local_ts = fec2::0/16 + remote_ts = fec1::0/16 + + updown = /etc/updown + updown = /usr/local/libexec/ipsec/_updown iptables + esp_proposals = aes128gcm128-x25519 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-x25519 + } +} + +authorities { + strongswan { + cacert = strongswanCert.pem + crl_uris = http://ip6-winnetou.strongswan.org/strongswan.crl + } +} \ No newline at end of file diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/updown b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/updown new file mode 100755 index 000000000..40b8fd303 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/hosts/sun/etc/updown @@ -0,0 +1,59 @@ +#!/bin/sh + +TUN_NAME=ipsec0 + +# use protocol specific options to set ports +case "$PLUTO_MY_PROTOCOL" in +1) # ICMP + ICMP_TYPE_OPTION="--icmp-type" + ;; +58) # ICMPv6 + ICMP_TYPE_OPTION="--icmpv6-type" + ;; +*) + ;; +esac + +# are there port numbers? +if [ "$PLUTO_MY_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + S_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + D_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + else + S_MY_PORT="--sport $PLUTO_MY_PORT" + D_MY_PORT="--dport $PLUTO_MY_PORT" + fi +fi +if [ "$PLUTO_PEER_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + # the syntax is --icmp[v6]-type type[/code], so add it to the existing option + S_MY_PORT="$S_MY_PORT/$PLUTO_PEER_PORT" + D_MY_PORT="$D_MY_PORT/$PLUTO_PEER_PORT" + else + S_PEER_PORT="--sport $PLUTO_PEER_PORT" + D_PEER_PORT="--dport $PLUTO_PEER_PORT" + fi +fi + +case "$PLUTO_VERB" in +up-client-v6) + ip6tables -I FORWARD 1 -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + ip6tables -I FORWARD 1 -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +down-client-v6) + ip6tables -D FORWARD -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + ip6tables -D FORWARD -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +esac diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/posttest.dat b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/posttest.dat new file mode 100644 index 000000000..74281868f --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/posttest.dat @@ -0,0 +1,11 @@ +moon::swanctl --terminate --ike gw-gw 2> /dev/null +moon::systemctl stop strongswan +sun::systemctl stop strongswan +alice::"ip route del fec2:\:/16 via fec1:\:1" +moon::"ip route del fec2:\:/16 via fec0:\:2" +sun::"ip route del fec1:\:/16 via fec0:\:1" +bob::"ip route del fec1:\:/16 via fec2:\:1" +moon::iptables-restore < /etc/iptables.flush +sun::iptables-restore < /etc/iptables.flush +moon::ip6tables-restore < /etc/ip6tables.flush +sun::ip6tables-restore < /etc/ip6tables.flush diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/pretest.dat b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/pretest.dat new file mode 100644 index 000000000..4ae22dc24 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/pretest.dat @@ -0,0 +1,13 @@ +moon::iptables-restore < /etc/iptables.drop +sun::iptables-restore < /etc/iptables.drop +moon::ip6tables-restore < /etc/ip6tables.rules +sun::ip6tables-restore < /etc/ip6tables.rules +alice::"ip route add fec2:\:/16 via fec1:\:1" +moon::"ip route add fec2:\:/16 via fec0:\:2" +sun::"ip route add fec1:\:/16 via fec0:\:1" +bob::"ip route add fec1:\:/16 via fec2:\:1" +moon::systemctl start strongswan +sun::systemctl start strongswan +moon::expect-connection gw-gw +sun::expect-connection gw-gw +moon::swanctl --initiate --child net-net 2> /dev/null diff --git a/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/test.conf b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/test.conf new file mode 100644 index 000000000..5906883b1 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-ip6-in-ip6-raw/test.conf @@ -0,0 +1,29 @@ +#!/bin/bash +# +# This configuration file provides information on the +# guest instances used for this test + +# All guest instances that are required for this test +# +VIRTHOSTS="alice moon winnetou sun bob" + +# Corresponding block diagram +# +DIAGRAM="a-m-w-s-b-ip6.png" + +# Guest instances on which tcpdump is to be started +# +TCPDUMPHOSTS="sun" + +# Guest instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon sun" + +# IP protocol used by IPsec is IPv6 +# +IPV6=1 + +# charon controlled by swanctl +# +SWANCTL=1 diff --git a/testing/tests/libipsec/net2net-cert-raw/description.txt b/testing/tests/libipsec/net2net-cert-raw/description.txt new file mode 100644 index 000000000..240f6e8e8 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/description.txt @@ -0,0 +1,9 @@ +A connection between the subnets behind the gateways moon and sun is set up. +The authentication is based on X.509 certificates and the kernel-libipsec +plugin is used for userland IPsec ESP encryption. In this scenario, UDP encapsulation +isn't enforced by the plugin as sending of raw ESP packets is enabled. +

+Upon the successful establishment of the IPsec tunnel, an updown script automatically +inserts iptables-based firewall rules that let pass the traffic tunneled via the +ipsec0 tun interface. In order to test both tunnel and firewall, client alice +behind gateway moon pings client bob located behind gateway sun. diff --git a/testing/tests/libipsec/net2net-cert-raw/evaltest.dat b/testing/tests/libipsec/net2net-cert-raw/evaltest.dat new file mode 100644 index 000000000..1b4b3fb10 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/evaltest.dat @@ -0,0 +1,5 @@ +alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES +moon:: swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=500 local-id=moon.strongswan.org remote-host=192.168.0.2 remote-port=500 remote-id=sun.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*net-net.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.0/16] remote-ts=\[10.2.0.0/16]::YES +sun::swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=192.168.0.2 local-port=500 local-id=sun.strongswan.org remote-host=192.168.0.1 remote-port=500 remote-id=moon.strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*net-net.*reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.2.0.0/16] remote-ts=\[10.1.0.0/16]::YES +sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES +sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES diff --git a/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/strongswan.conf b/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..e2c90b0bf --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/strongswan.conf @@ -0,0 +1,15 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon-systemd { + load = random nonce aes sha1 sha2 gcm pem pkcs1 curve25519 gmp x509 curl revocation hmac kdf vici kernel-libipsec kernel-netlink socket-default updown + multiple_authentication = no + plugins { + kernel-libipsec { + raw_esp = yes + } + } +} diff --git a/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..b063e600d --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/swanctl/swanctl.conf @@ -0,0 +1,29 @@ +connections { + + gw-gw { + local_addrs = 192.168.0.1 + remote_addrs = 192.168.0.2 + + local { + auth = pubkey + certs = moonCert.pem + id = moon.strongswan.org + } + remote { + auth = pubkey + id = sun.strongswan.org + } + children { + net-net { + local_ts = 10.1.0.0/16 + remote_ts = 10.2.0.0/16 + + updown = /etc/updown + esp_proposals = aes128gcm128-x25519 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-x25519 + } +} diff --git a/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/updown b/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/updown new file mode 100755 index 000000000..682ccc701 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/hosts/moon/etc/updown @@ -0,0 +1,59 @@ +#!/bin/sh + +TUN_NAME=ipsec0 + +# use protocol specific options to set ports +case "$PLUTO_MY_PROTOCOL" in +1) # ICMP + ICMP_TYPE_OPTION="--icmp-type" + ;; +58) # ICMPv6 + ICMP_TYPE_OPTION="--icmpv6-type" + ;; +*) + ;; +esac + +# are there port numbers? +if [ "$PLUTO_MY_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + S_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + D_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + else + S_MY_PORT="--sport $PLUTO_MY_PORT" + D_MY_PORT="--dport $PLUTO_MY_PORT" + fi +fi +if [ "$PLUTO_PEER_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + # the syntax is --icmp[v6]-type type[/code], so add it to the existing option + S_MY_PORT="$S_MY_PORT/$PLUTO_PEER_PORT" + D_MY_PORT="$D_MY_PORT/$PLUTO_PEER_PORT" + else + S_PEER_PORT="--sport $PLUTO_PEER_PORT" + D_PEER_PORT="--dport $PLUTO_PEER_PORT" + fi +fi + +case "$PLUTO_VERB" in +up-client) + iptables -I FORWARD 1 -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + iptables -I FORWARD 1 -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +down-client) + iptables -D FORWARD -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + iptables -D FORWARD -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +esac diff --git a/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/strongswan.conf b/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/strongswan.conf new file mode 100644 index 000000000..fa2a2a49c --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/strongswan.conf @@ -0,0 +1,15 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon-systemd { + load = random nonce aes sha1 sha2 gcm pem pkcs1 curve25519 gmp x509 curl revocation hmac kdf vici ker_nel-libipsec kernel-netlink socket-default updown + multiple_authentication = no + plugins { + kernel-libipsec { + raw_esp = yes + } + } +} diff --git a/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/swanctl/swanctl.conf b/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..36229552b --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/swanctl/swanctl.conf @@ -0,0 +1,30 @@ +connections { + + gw-gw { + local_addrs = 192.168.0.2 + remote_addrs = 192.168.0.1 + + local { + auth = pubkey + certs = sunCert.pem + id = sun.strongswan.org + } + remote { + auth = pubkey + id = moon.strongswan.org + } + children { + net-net { + local_ts = 10.2.0.0/16 + remote_ts = 10.1.0.0/16 + + updown = /etc/updown + updown = /usr/local/libexec/ipsec/_updown iptables + esp_proposals = aes128gcm128-x25519 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-x25519 + } +} diff --git a/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/updown b/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/updown new file mode 100755 index 000000000..682ccc701 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/hosts/sun/etc/updown @@ -0,0 +1,59 @@ +#!/bin/sh + +TUN_NAME=ipsec0 + +# use protocol specific options to set ports +case "$PLUTO_MY_PROTOCOL" in +1) # ICMP + ICMP_TYPE_OPTION="--icmp-type" + ;; +58) # ICMPv6 + ICMP_TYPE_OPTION="--icmpv6-type" + ;; +*) + ;; +esac + +# are there port numbers? +if [ "$PLUTO_MY_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + S_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + D_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT" + else + S_MY_PORT="--sport $PLUTO_MY_PORT" + D_MY_PORT="--dport $PLUTO_MY_PORT" + fi +fi +if [ "$PLUTO_PEER_PORT" != 0 ] +then + if [ -n "$ICMP_TYPE_OPTION" ] + then + # the syntax is --icmp[v6]-type type[/code], so add it to the existing option + S_MY_PORT="$S_MY_PORT/$PLUTO_PEER_PORT" + D_MY_PORT="$D_MY_PORT/$PLUTO_PEER_PORT" + else + S_PEER_PORT="--sport $PLUTO_PEER_PORT" + D_PEER_PORT="--dport $PLUTO_PEER_PORT" + fi +fi + +case "$PLUTO_VERB" in +up-client) + iptables -I FORWARD 1 -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + iptables -I FORWARD 1 -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +down-client) + iptables -D FORWARD -o $TUN_NAME -p $PLUTO_PEER_PROTOCOL \ + -s $PLUTO_MY_CLIENT $S_MY_PORT \ + -d $PLUTO_PEER_CLIENT $D_PEER_PORT -j ACCEPT + iptables -D FORWARD -i $TUN_NAME -p $PLUTO_MY_PROTOCOL \ + -s $PLUTO_PEER_CLIENT $S_PEER_PORT \ + -d $PLUTO_MY_CLIENT $D_MY_PORT -j ACCEPT + ;; +esac diff --git a/testing/tests/libipsec/net2net-cert-raw/posttest.dat b/testing/tests/libipsec/net2net-cert-raw/posttest.dat new file mode 100644 index 000000000..cc6a5bff7 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/posttest.dat @@ -0,0 +1,5 @@ +moon::swanctl --terminate --ike gw-gw 2> /dev/null +moon::systemctl stop strongswan +sun::systemctl stop strongswan +moon::iptables-restore < /etc/iptables.flush +sun::iptables-restore < /etc/iptables.flush diff --git a/testing/tests/libipsec/net2net-cert-raw/pretest.dat b/testing/tests/libipsec/net2net-cert-raw/pretest.dat new file mode 100644 index 000000000..2d3c8c1e2 --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/pretest.dat @@ -0,0 +1,7 @@ +moon::iptables-restore < /etc/iptables.rules +sun::iptables-restore < /etc/iptables.rules +moon::systemctl start strongswan +sun::systemctl start strongswan +moon::expect-connection gw-gw +sun::expect-connection gw-gw +moon::swanctl --initiate --child net-net 2> /dev/null diff --git a/testing/tests/libipsec/net2net-cert-raw/test.conf b/testing/tests/libipsec/net2net-cert-raw/test.conf new file mode 100644 index 000000000..87abc763b --- /dev/null +++ b/testing/tests/libipsec/net2net-cert-raw/test.conf @@ -0,0 +1,25 @@ +#!/bin/bash +# +# This configuration file provides information on the +# guest instances used for this test + +# All guest instances that are required for this test +# +VIRTHOSTS="alice moon winnetou sun bob" + +# Corresponding block diagram +# +DIAGRAM="a-m-w-s-b.png" + +# Guest instances on which tcpdump is to be started +# +TCPDUMPHOSTS="sun" + +# Guest instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon sun" + +# charon controlled by swanctl +# +SWANCTL=1