Merge branch 'libipsec-raw-esp'
This adds support for sending/receiving ESP packets without UDP encapsulation to libipsec and kernel-libipsec. Only Linux is currently supported and the feature is disabled by default.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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_ @}*/
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+21
-6
@@ -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,
|
||||
);
|
||||
|
||||
+15
-1
@@ -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
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
A connection between the hosts <b>moon</b> and <b>sun</b> is set up.
|
||||
The authentication is based on <b>X.509 certificates</b> and the <b>kernel-libipsec</b>
|
||||
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.
|
||||
<b>Firewall marks</b> are used to make the direct ESP connection possible and
|
||||
still allow IKE traffic to flow freely between the two hosts.
|
||||
<p/>
|
||||
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
|
||||
<b>ipsec0</b> tun interface. In order to test both host-to-host tunnel and firewall,
|
||||
<b>moon</b> pings <b>sun</b>.
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
+2
-2
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
An IPv6 ESP tunnel connection between the gateways <b>moon</b> and <b>sun</b> is set up.
|
||||
It connects the two IPv6 subnets hiding behind their respective gateways.
|
||||
The authentication is based on <b>X.509 certificates</b> and the <b>kernel-libipsec</b>
|
||||
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.
|
||||
<p/>
|
||||
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
|
||||
<b>ipsec0</b> tun interface. In order to test both tunnel and firewall, client <b>alice</b>
|
||||
behind gateway <b>moon</b> sends an IPv6 ICMP request to client <b>bob</b> behind <b>sun</b>
|
||||
using the ping6 command.
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,9 @@
|
||||
A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b> is set up.
|
||||
The authentication is based on <b>X.509 certificates</b> and the <b>kernel-libipsec</b>
|
||||
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.
|
||||
<p/>
|
||||
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
|
||||
<b>ipsec0</b> tun interface. In order to test both tunnel and firewall, client <b>alice</b>
|
||||
behind gateway <b>moon</b> pings client <b>bob</b> located behind gateway <b>sun</b>.
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user