Merge branch 'forecast'

Implement a forecast plugin that supports forwarding of multi- and broadcast
messages between a LAN and clients or between connected clients. It uses
IPsec policy marks to send packets over multiple identical multi- and broadcast
policies.
This commit is contained in:
Martin Willi
2015-02-20 16:34:56 +01:00
24 changed files with 1673 additions and 0 deletions
+7
View File
@@ -12,6 +12,13 @@
same NAT device for client-initiated flows. A common use case is to protect
L2TP/IPsec, as supported by some systems.
- The forecast plugin can forward broadcast and multicast messages between
connected clients and a LAN. For CHILD_SA using unique marks, it sets up
the required Netfilter rules and uses a multicast/broadcast listener that
forwards such messages to all connected clients. This plugin is designed for
Windows 7 IKEv2 clients, which announces its services over the tunnel if the
negotiated IPsec policy allows it.
strongswan-5.2.2
----------------
+1
View File
@@ -46,6 +46,7 @@ plugins = \
plugins/eap-ttls.opt \
plugins/error-notify.opt \
plugins/ext-auth.opt \
plugins/forecast.opt \
plugins/gcrypt.opt \
plugins/ha.opt \
plugins/imc-attestation.opt \
+29
View File
@@ -0,0 +1,29 @@
charon.plugins.forecast.interface =
Local interface to listen for broadcasts to forward.
Name of the local interface to listen for broadcasts messages to forward.
If no interface is configured, the first usable interface is used, which
is usually just fine for single-homed hosts. If your host has multiple
interfaces, set this option to the local LAN interface you want to forward
broadcasts from/to.
charon.plugins.forecast.reinject =
CHILD_SA configurations names to perform multi/broadcast reinjection.
Comma separated list of CHILD_SA configuration names for which to perform
multi/broadcast reinjection. For clients connecting over such a
configuration, any multi/broadcast received over the tunnel gets reinjected
to all active tunnels. This makes the broadcasts visible to other peers,
and for examples allows clients to see others shares. If disabled,
multi/broadcast messages received over a tunnel are injected to the local
network only, but not to other IPsec clients.
charon.plugins.forecast.groups = 224.0.0.1,224.0.0.22,224.0.0.251,224.0.0.252,239.255.255.250
Multicast groups to join locally, allowing forwarding of them.
Comma separated list of multicast groups to join locally. The local host
receives and forwards packets in the local LAN for joined multicast groups
only. Packets matching the list of multicast groups get forwarded to
connected clients. The default group includes host multicasts, IGMP, mDNS,
LLMNR and SSDP/WS-Discovery, and is usually a good choice for Windows
clients.
+4
View File
@@ -247,6 +247,7 @@ ARG_ENABL_SET([tnccs-dynamic], [enable dynamic TNCCS protocol discovery module.
ARG_ENABL_SET([android-log], [enable Android specific logger plugin.])
ARG_ENABL_SET([certexpire], [enable CSV export of expiration dates of used certificates.])
ARG_ENABL_SET([connmark], [enable connmark plugin using conntrack based marks to select return path SA.])
ARG_ENABL_SET([forecast], [enable forecast plugin forwarding broadcast/multicast messages.])
ARG_ENABL_SET([duplicheck], [advanced duplicate checking plugin using liveness checks.])
ARG_ENABL_SET([error-notify], [enable error notification plugin.])
ARG_ENABL_SET([farp], [enable ARP faking plugin that responds to ARP requests to peers virtual IP])
@@ -1270,6 +1271,7 @@ ADD_PLUGIN([socket-default], [c charon nm cmd])
ADD_PLUGIN([socket-dynamic], [c charon cmd])
ADD_PLUGIN([socket-win], [c charon])
ADD_PLUGIN([connmark], [c charon])
ADD_PLUGIN([forecast], [c charon])
ADD_PLUGIN([farp], [c charon])
ADD_PLUGIN([stroke], [c charon])
ADD_PLUGIN([vici], [c charon])
@@ -1478,6 +1480,7 @@ AM_CONDITIONAL(USE_SOCKET_DEFAULT, test x$socket_default = xtrue)
AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue)
AM_CONDITIONAL(USE_SOCKET_WIN, test x$socket_win = xtrue)
AM_CONDITIONAL(USE_CONNMARK, test x$connmark = xtrue)
AM_CONDITIONAL(USE_FORECAST, test x$forecast = xtrue)
AM_CONDITIONAL(USE_FARP, test x$farp = xtrue)
AM_CONDITIONAL(USE_ADDRBLOCK, test x$addrblock = xtrue)
AM_CONDITIONAL(USE_UNITY, test x$unity = xtrue)
@@ -1713,6 +1716,7 @@ AC_CONFIG_FILES([
src/libcharon/plugins/socket_dynamic/Makefile
src/libcharon/plugins/socket_win/Makefile
src/libcharon/plugins/connmark/Makefile
src/libcharon/plugins/forecast/Makefile
src/libcharon/plugins/farp/Makefile
src/libcharon/plugins/smp/Makefile
src/libcharon/plugins/sql/Makefile
+7
View File
@@ -216,6 +216,13 @@ if MONOLITHIC
endif
endif
if USE_FORECAST
SUBDIRS += plugins/forecast
if MONOLITHIC
libcharon_la_LIBADD += plugins/forecast/libstrongswan-forecast.la
endif
endif
if USE_FARP
SUBDIRS += plugins/farp
if MONOLITHIC
@@ -0,0 +1,21 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libhydra \
-I$(top_srcdir)/src/libcharon
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-forecast.la
else
plugin_LTLIBRARIES = libstrongswan-forecast.la
endif
libstrongswan_forecast_la_SOURCES = \
forecast_listener.h forecast_listener.c \
forecast_forwarder.h forecast_forwarder.c \
forecast_plugin.h forecast_plugin.c
libstrongswan_forecast_la_LDFLAGS = -module -avoid-version
libstrongswan_forecast_la_LIBADD = -lip4tc
@@ -0,0 +1,496 @@
/*
* Copyright (C) 2010-2014 Martin Willi
* Copyright (C) 2010-2014 revosec 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.
*/
#include "forecast_forwarder.h"
#include <errno.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <linux/socket.h>
#include <netinet/if_ether.h>
#include <linux/if_packet.h>
#include <linux/filter.h>
#include <sys/ioctl.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <hydra.h>
#include <daemon.h>
#include <threading/thread.h>
#include <processing/jobs/callback_job.h>
#define BOOTP_SERVER_PORT 67
#define BOOTP_CLIENT_PORT 68
typedef struct private_forecast_forwarder_t private_forecast_forwarder_t;
typedef struct private_kernel_listener_t private_kernel_listener_t;
/**
* Private data of registered kernel listener
*/
struct private_kernel_listener_t {
/**
* Implements kernel_listener_t
*/
kernel_listener_t listener;
/**
* Listener that knows active addresses
*/
forecast_listener_t *fc;
/**
* current broadcast address of internal network
*/
u_int32_t broadcast;
/**
* LAN interface index
*/
int ifindex;
/**
* Packet socket
*/
int pkt;
/**
* RAW socket
*/
int raw;
};
/**
* Private data of an forecast_forwarder_t object.
*/
struct private_forecast_forwarder_t {
/**
* Public forecast_forwarder_t interface.
*/
forecast_forwarder_t public;
/**
* Public kernel_listener_t interface.
*/
private_kernel_listener_t kernel;
};
/**
* Send a broadcast/multicast packet to a network
*/
static void send_net(private_forecast_forwarder_t *this,
struct sockaddr_ll *addr, void *buf, size_t len)
{
if (sendto(this->kernel.pkt, buf, len, 0,
(struct sockaddr*)addr, sizeof(*addr)) != len)
{
DBG1(DBG_NET, "forecast send_net() failed: %s", strerror(errno));
}
}
/**
* Send a broadcast/multicast packet to a peer
*/
static void send_peer(private_forecast_forwarder_t *this, u_int32_t dst,
void *buf, size_t len, int mark)
{
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = dst,
};
if (setsockopt(this->kernel.raw, SOL_SOCKET, SO_MARK,
&mark, sizeof(mark)) != 0)
{
DBG1(DBG_NET, "forecast setting SO_MARK failed: %s", strerror(errno));
}
if (sendto(this->kernel.raw, buf, len, 0,
(struct sockaddr*)&addr, sizeof(addr)) != len)
{
DBG1(DBG_NET, "forecast send_peer() failed: %s", strerror(errno));
}
}
/**
* Check if an IP packet is BOOTP/DHCP
*/
static bool is_bootp(void *buf, size_t len)
{
struct __attribute__((__packed__)) {
struct iphdr ip;
struct udphdr udp;
} *pkt = buf;
if (len > sizeof(*pkt))
{
if (ntohs(pkt->udp.source) == BOOTP_CLIENT_PORT &&
ntohs(pkt->udp.dest) == BOOTP_SERVER_PORT)
{
return TRUE;
}
if (ntohs(pkt->udp.source) == BOOTP_SERVER_PORT &&
ntohs(pkt->udp.dest) == BOOTP_CLIENT_PORT)
{
return TRUE;
}
}
return FALSE;
}
/**
* Broadcast/Multicast receiver
*/
static bool receive_casts(private_forecast_forwarder_t *this)
{
struct __attribute__((packed)) {
struct iphdr hdr;
char data[2048];
} buf;
char *type;
ssize_t len;
u_int mark, origin = 0;
host_t *src, *dst;
traffic_selector_t *ts;
enumerator_t *enumerator;
struct sockaddr_ll addr;
socklen_t alen = sizeof(addr);
bool reinject;
len = recvfrom(this->kernel.pkt, &buf, sizeof(buf), MSG_DONTWAIT,
(struct sockaddr*)&addr, &alen);
if (len < 0)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
{
DBG1(DBG_NET, "receiving from forecast socket failed: %s",
strerror(errno));
}
return TRUE;
}
else if (len < sizeof(struct iphdr))
{
DBG1(DBG_NET, "received short forecast packet: %zd bytes", len);
return TRUE;
}
if (is_bootp(&buf, len))
{ /* don't forward DHCP broadcasts */
return TRUE;
}
src = host_create_from_chunk(AF_INET, chunk_from_thing(buf.hdr.saddr), 0);
dst = host_create_from_chunk(AF_INET, chunk_from_thing(buf.hdr.daddr), 0);
/* create valid broadcast/multicast MAC to send out */
if (IN_MULTICAST(ntohl(buf.hdr.daddr)))
{
type = "multi";
ETHER_MAP_IP_MULTICAST(&buf.hdr.daddr, addr.sll_addr);
}
else
{
type = "broad";
memset(&addr.sll_addr, 0xFF, sizeof(addr.sll_addr));
}
DBG2(DBG_NET, "forecast intercepted packet: %H to %H", src, dst);
/* find mark of originating tunnel */
enumerator = this->kernel.fc->create_enumerator(this->kernel.fc, FALSE);
while (enumerator->enumerate(enumerator, &ts, &mark, &reinject))
{
if (ts->includes(ts, src))
{
origin = mark;
break;
}
}
enumerator->destroy(enumerator);
/* send packet over all tunnels, but not the packets origin */
enumerator = this->kernel.fc->create_enumerator(this->kernel.fc, FALSE);
while (enumerator->enumerate(enumerator, &ts, &mark, &reinject))
{
if (ts->includes(ts, dst))
{
if ((reinject && origin != mark) || origin == 0)
{
DBG2(DBG_NET, "forwarding a %H %scast from %H to peer %R (%u)",
dst, type, src, ts, mark);
send_peer(this, buf.hdr.daddr, &buf, len, mark);
}
}
}
enumerator->destroy(enumerator);
if (origin)
{
/* forward broadcast/multicast from client to network */
DBG2(DBG_NET, "forwarding a %H %scast from peer %H to internal network",
dst, type, src);
addr.sll_ifindex = this->kernel.ifindex;
send_net(this, &addr, &buf, len);
}
dst->destroy(dst);
src->destroy(src);
return TRUE;
}
/**
* Join a multicast group
*/
static void join_group(private_kernel_listener_t *this, char *group,
struct sockaddr *addr)
{
struct sockaddr_in *in;
struct ip_mreqn mreq;
host_t *host;
host = host_create_from_string(group, 0);
if (host)
{
memset(&mreq, 0, sizeof(mreq));
memcpy(&mreq.imr_multiaddr.s_addr, host->get_address(host).ptr, 4);
if (addr->sa_family == AF_INET)
{
in = (struct sockaddr_in*)addr;
memcpy(&mreq.imr_address, &in->sin_addr.s_addr,
sizeof(in->sin_addr.s_addr));
}
mreq.imr_ifindex = this->ifindex;
if (setsockopt(this->raw, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) == -1)
{
if (errno != EADDRINUSE)
{
DBG1(DBG_NET, "forecast multicast join to %s failed: %s",
group, strerror(errno));
}
}
else
{
DBG2(DBG_NET, "forwarding multicast group %s", group);
}
host->destroy(host);
}
}
/**
* (Re-)Join all multicast groups we want to forward
*/
static void join_groups(private_kernel_listener_t *this, struct sockaddr *addr)
{
enumerator_t *enumerator;
char *groups, *group;
static char *def =
"224.0.0.1," /* host multicast */
"224.0.0.22," /* IGMP */
"224.0.0.251," /* mDNS */
"224.0.0.252," /* LLMNR */
"239.255.255.250"; /* SSDP/WS-discovery */
groups = lib->settings->get_str(lib->settings,
"%s.plugins.forecast.groups", def, lib->ns);
DBG1(DBG_CFG, "joining forecast multicast groups: %s", groups);
enumerator = enumerator_create_token(groups, ",", " ");
while (enumerator->enumerate(enumerator, &group))
{
join_group(this, group, addr);
}
enumerator->destroy(enumerator);
}
/**
* Attach the socket filter to the socket
*/
static bool attach_filter(int fd, u_int32_t broadcast)
{
struct sock_filter filter_code[] = {
/* destination address: is ... */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct iphdr, daddr)),
/* broadcast, as received from the local network */
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ntohl(broadcast), 4, 0),
/* broadcast, as Win7 sends them */
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xFFFFFFFF, 3, 0),
/* any multicast, 224.0.0.0/4 */
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, 0xF0000000),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xE0000000, 1, 0),
BPF_STMT(BPF_RET+BPF_K, 0),
BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
BPF_STMT(BPF_RET+BPF_A, 0),
};
struct sock_fprog filter = {
sizeof(filter_code) / sizeof(struct sock_filter),
filter_code,
};
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER,
&filter, sizeof(filter)) < 0)
{
DBG1(DBG_NET, "installing forecast PACKET socket filter failed: %s",
strerror(errno));
return FALSE;
}
return TRUE;
}
/**
* Get the interface index of an interface name
*/
static int get_ifindex(private_kernel_listener_t *this, char *ifname)
{
struct ifreq ifr = {};
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(this->raw, SIOCGIFINDEX, &ifr) == 0)
{
return ifr.ifr_ifindex;
}
return 0;
}
/**
* Set up the interface for broad/multicast forwarding
*/
static void setup_interface(private_kernel_listener_t *this)
{
struct ifaddrs *addrs, *current;
struct sockaddr_in *in;
host_t *host;
char *name;
name = lib->settings->get_str(lib->settings,
"%s.plugins.forecast.interface", NULL, lib->ns);
if (getifaddrs(&addrs) == 0)
{
for (current = addrs; current; current = current->ifa_next)
{
if (name && !streq(name, current->ifa_name))
{
continue;
}
if (current->ifa_flags & IFF_BROADCAST &&
current->ifa_broadaddr &&
current->ifa_broadaddr->sa_family == AF_INET)
{
DBG1(DBG_NET, "using forecast interface %s", current->ifa_name);
this->ifindex = get_ifindex(this, current->ifa_name);
in = (struct sockaddr_in*)current->ifa_broadaddr;
attach_filter(this->pkt, in->sin_addr.s_addr);
join_groups(this, current->ifa_addr);
host = host_create_from_sockaddr(current->ifa_broadaddr);
if (host)
{
this->fc->set_broadcast(this->fc, host);
host->destroy(host);
}
break;
}
}
}
freeifaddrs(addrs);
}
METHOD(kernel_listener_t, roam, bool,
private_kernel_listener_t *this, bool address)
{
if (address)
{
setup_interface(this);
}
return TRUE;
}
METHOD(forecast_forwarder_t, destroy, void,
private_forecast_forwarder_t *this)
{
if (this->kernel.raw != -1)
{
close(this->kernel.raw);
}
if (this->kernel.pkt != -1)
{
lib->watcher->remove(lib->watcher, this->kernel.pkt);
close(this->kernel.pkt);
}
hydra->kernel_interface->remove_listener(hydra->kernel_interface,
&this->kernel.listener);
free(this);
}
/**
* See header
*/
forecast_forwarder_t *forecast_forwarder_create(forecast_listener_t *listener)
{
private_forecast_forwarder_t *this;
int on = 1;
INIT(this,
.public = {
.destroy = _destroy,
},
.kernel = {
.listener = {
.roam = _roam,
},
.raw = -1,
.pkt = -1,
.fc = listener,
},
);
this->kernel.pkt = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
if (this->kernel.pkt == -1)
{
DBG1(DBG_NET, "opening PACKET socket failed: %s", strerror(errno));
destroy(this);
return NULL;
}
this->kernel.raw = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (this->kernel.raw == -1)
{
DBG1(DBG_NET, "opening RAW socket failed: %s", strerror(errno));
destroy(this);
return NULL;
}
if (setsockopt(this->kernel.raw, IPPROTO_IP, IP_HDRINCL,
&on, sizeof(on)) == -1)
{
DBG1(DBG_NET, "forecast socket HDRINCL failed: %s", strerror(errno));
destroy(this);
return NULL;
}
if (setsockopt(this->kernel.raw, SOL_SOCKET, SO_BROADCAST,
&on, sizeof(on)) == -1)
{
DBG1(DBG_NET, "forecast socket BROADCAST failed: %s", strerror(errno));
destroy(this);
return NULL;
}
setup_interface(&this->kernel);
hydra->kernel_interface->add_listener(hydra->kernel_interface,
&this->kernel.listener);
lib->watcher->add(lib->watcher, this->kernel.pkt, WATCHER_READ,
(watcher_cb_t)receive_casts, this);
return &this->public;
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2010-2014 Martin Willi
* Copyright (C) 2010-2014 revosec 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 forecast_forwarder forecast_forwarder
* @{ @ingroup forecast
*/
#ifndef FORECAST_FORWARDER_H_
#define FORECAST_FORWARDER_H_
#include "forecast_listener.h"
typedef struct forecast_forwarder_t forecast_forwarder_t;
/**
* Broadcast/Multicast sniffer and forwarder.
*/
struct forecast_forwarder_t {
/**
* Destroy a forecast_forwarder_t.
*/
void (*destroy)(forecast_forwarder_t *this);
};
/**
* Create a forecast_forwarder instance.
*
* @param listener listener to check for addresses to forward to
* @return forwarder instance
*/
forecast_forwarder_t *forecast_forwarder_create(forecast_listener_t *listener);
#endif /** FORECAST_FORWARDER_H_ @}*/
@@ -0,0 +1,680 @@
/*
* Copyright (C) 2010-2014 Martin Willi
* Copyright (C) 2010-2014 revosec 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.
*/
#include "forecast_listener.h"
#include <errno.h>
#include <libiptc/libiptc.h>
#include <linux/netfilter/xt_MARK.h>
#include <linux/netfilter/xt_esp.h>
#include <daemon.h>
#include <collections/array.h>
#include <collections/hashtable.h>
#include <threading/rwlock.h>
typedef struct private_forecast_listener_t private_forecast_listener_t;
/**
* Private data of an forecast_listener_t object.
*/
struct private_forecast_listener_t {
/**
* Public forecast_listener_t interface.
*/
forecast_listener_t public;
/**
* List of entries
*/
linked_list_t *entries;
/**
* RWlock for IP list
*/
rwlock_t *lock;
/**
* Configs we do reinjection
*/
char *reinject_configs;
/**
* Broadcast address on LAN interface, network order
*/
u_int32_t broadcast;
};
/**
* Hashtable entry
*/
typedef struct {
/** local traffic selectors */
array_t *lts;
/** remote traffic selectors */
array_t *rts;
/** firewall mark used by CHILD_SA */
u_int mark;
/** local IKE_SA endpoint */
host_t *lhost;
/** remote IKE_SA endpoint */
host_t *rhost;
/** inbound SPI */
u_int32_t spi;
/** use UDP encapsulation */
bool encap;
/** wheter we should allow reencapsulation of IPsec received forecasts */
bool reinject;
/** broadcast address used for that entry */
u_int32_t broadcast;
} entry_t;
/**
* Destroy an entry
*/
static void entry_destroy(entry_t *entry)
{
if (entry)
{
entry->lhost->destroy(entry->lhost);
entry->rhost->destroy(entry->rhost);
array_destroy_offset(entry->lts, offsetof(traffic_selector_t, destroy));
array_destroy_offset(entry->rts, offsetof(traffic_selector_t, destroy));
free(entry);
}
}
/**
* Convert an (IPv4) traffic selector to an address and mask
*/
static bool ts2in(traffic_selector_t *ts,
struct in_addr *addr, struct in_addr *mask)
{
u_int8_t bits;
host_t *net;
if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE &&
ts->to_subnet(ts, &net, &bits))
{
memcpy(&addr->s_addr, net->get_address(net).ptr, 4);
net->destroy(net);
mask->s_addr = htonl(0xffffffffU << (32 - bits));
return TRUE;
}
return FALSE;
}
/**
* Convert an (IPv4) host to an address with mask
*/
static bool host2in(host_t *host, struct in_addr *addr, struct in_addr *mask)
{
if (host->get_family(host) == AF_INET)
{
memcpy(&addr->s_addr, host->get_address(host).ptr, 4);
mask->s_addr = ~0;
return TRUE;
}
return FALSE;
}
/**
* Add or remove a rule to/from the specified chain
*/
static bool manage_rule(struct iptc_handle *ipth, const char *chain,
bool add, struct ipt_entry *e)
{
if (add)
{
if (!iptc_insert_entry(chain, e, 0, ipth))
{
DBG1(DBG_CFG, "appending %s rule failed: %s",
chain, iptc_strerror(errno));
return FALSE;
}
}
else
{
if (!iptc_delete_entry(chain, e, "", ipth))
{
DBG1(DBG_CFG, "deleting %s rule failed: %s",
chain, iptc_strerror(errno));
return FALSE;
}
}
return TRUE;
}
/**
* Add rule marking UDP-encapsulated ESP packets to match the correct policy
*/
static bool manage_pre_esp_in_udp(struct iptc_handle *ipth,
entry_t *entry, bool add)
{
struct {
struct ipt_entry e;
struct ipt_entry_match m;
struct xt_udp udp;
struct ipt_entry_target t;
struct xt_mark_tginfo2 tm;
} ipt = {
.e = {
.target_offset = XT_ALIGN(sizeof(ipt.e) + sizeof(ipt.m) +
sizeof(ipt.udp)),
.next_offset = sizeof(ipt),
.ip = {
.proto = IPPROTO_UDP,
},
},
.m = {
.u = {
.user = {
.match_size = XT_ALIGN(sizeof(ipt.m) + sizeof(ipt.udp)),
.name = "udp",
},
},
},
.udp = {
.spts = {
entry->rhost->get_port(entry->rhost),
entry->rhost->get_port(entry->lhost)
},
.dpts = {
entry->lhost->get_port(entry->lhost),
entry->lhost->get_port(entry->lhost)
},
},
.t = {
.u = {
.user = {
.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.tm)),
.name = "MARK",
.revision = 2,
},
},
},
.tm = {
.mark = entry->mark,
.mask = ~0,
},
};
if (!host2in(entry->lhost, &ipt.e.ip.dst, &ipt.e.ip.dmsk) ||
!host2in(entry->rhost, &ipt.e.ip.src, &ipt.e.ip.smsk))
{
return FALSE;
}
return manage_rule(ipth, "PREROUTING", add, &ipt.e);
}
/**
* Add rule marking non-encapsulated ESP packets to match the correct policy
*/
static bool manage_pre_esp(struct iptc_handle *ipth, entry_t *entry, bool add)
{
struct {
struct ipt_entry e;
struct ipt_entry_match m;
struct xt_esp esp;
struct ipt_entry_target t;
struct xt_mark_tginfo2 tm;
} ipt = {
.e = {
.target_offset = XT_ALIGN(sizeof(ipt.e) + sizeof(ipt.m) +
sizeof(ipt.esp)),
.next_offset = sizeof(ipt),
.ip = {
.proto = IPPROTO_ESP,
},
},
.m = {
.u = {
.user = {
.match_size = XT_ALIGN(sizeof(ipt.m) + sizeof(ipt.esp)),
.name = "esp",
},
},
},
.esp = {
.spis = { htonl(entry->spi), htonl(entry->spi) },
},
.t = {
.u = {
.user = {
.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.tm)),
.name = "MARK",
.revision = 2,
},
},
},
.tm = {
.mark = entry->mark,
.mask = ~0,
},
};
if (!host2in(entry->lhost, &ipt.e.ip.dst, &ipt.e.ip.dmsk) ||
!host2in(entry->rhost, &ipt.e.ip.src, &ipt.e.ip.smsk))
{
return FALSE;
}
return manage_rule(ipth, "PREROUTING", add, &ipt.e);
}
/**
* Add rule marking ESP packets to match the correct policy
*/
static bool manage_pre(struct iptc_handle *ipth, entry_t *entry, bool add)
{
if (entry->encap)
{
return manage_pre_esp_in_udp(ipth, entry, add);
}
return manage_pre_esp(ipth, entry, add);
}
/**
* Add rule handling outbound traffic to use correct mark
*/
static bool manage_out(struct iptc_handle *ipth, entry_t *entry, bool add)
{
struct {
struct ipt_entry e;
struct ipt_entry_target t;
struct xt_mark_tginfo2 m;
} ipt = {
.e = {
.target_offset = XT_ALIGN(sizeof(ipt.e)),
.next_offset = sizeof(ipt),
},
.t = {
.u.user.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.m)),
.u.user.name = "MARK",
.u.user.revision = 2,
},
.m = {
.mark = entry->mark,
.mask = ~0,
},
};
enumerator_t *enumerator;
traffic_selector_t *ts;
enumerator = array_create_enumerator(entry->rts);
while (enumerator->enumerate(enumerator, &ts))
{
if (!ts2in(ts, &ipt.e.ip.dst, &ipt.e.ip.dmsk))
{
continue;
}
if (ipt.e.ip.dst.s_addr == 0xffffffff ||
ipt.e.ip.dst.s_addr == entry->broadcast ||
memeq(&ipt.e.ip.dst.s_addr, "\xe0", 1))
{
/* skip broadcast/multicast selectors, they are shared and the mark
* is set by the socket we use for reinjection */
continue;
}
if (!manage_rule(ipth, "PREROUTING", add, &ipt.e) ||
!manage_rule(ipth, "OUTPUT", add, &ipt.e))
{
enumerator->destroy(enumerator);
return FALSE;
}
}
enumerator->destroy(enumerator);
return TRUE;
}
/**
* Check if config is whitelisted to reinject traffic
*/
static bool is_reinject_config(private_forecast_listener_t *this, char *name)
{
enumerator_t *enumerator;
bool reinject = FALSE;
char *token;
enumerator = enumerator_create_token(this->reinject_configs, ",", " ");
while (enumerator->enumerate(enumerator, &token))
{
if (streq(token, name))
{
reinject = TRUE;
break;
}
}
enumerator->destroy(enumerator);
return reinject;
}
/**
* Add rules and entry for given CHILD_SA
*/
static bool add_entry(private_forecast_listener_t *this,
struct iptc_handle *ipth, host_t *lhost, host_t *rhost,
child_sa_t *child_sa, bool encap)
{
enumerator_t *enumerator;
traffic_selector_t *ts;
entry_t *entry;
INIT(entry,
.lts = array_create(0, 0),
.rts = array_create(0, 0),
.lhost = lhost->clone(lhost),
.rhost = rhost->clone(rhost),
.spi = child_sa->get_spi(child_sa, TRUE),
.encap = encap,
.mark = child_sa->get_mark(child_sa, TRUE).value,
.reinject = is_reinject_config(this, child_sa->get_name(child_sa)),
.broadcast = this->broadcast,
);
enumerator = child_sa->create_ts_enumerator(child_sa, TRUE);
while (enumerator->enumerate(enumerator, &ts))
{
array_insert(entry->lts, ARRAY_TAIL, ts->clone(ts));
}
enumerator->destroy(enumerator);
enumerator = child_sa->create_ts_enumerator(child_sa, FALSE);
while (enumerator->enumerate(enumerator, &ts))
{
array_insert(entry->rts, ARRAY_TAIL, ts->clone(ts));
}
enumerator->destroy(enumerator);
if (manage_pre(ipth, entry, TRUE) &&
manage_out(ipth, entry, TRUE))
{
this->lock->write_lock(this->lock);
this->entries->insert_last(this->entries, entry);
this->lock->unlock(this->lock);
return TRUE;
}
entry_destroy(entry);
return FALSE;
}
/**
* Remove an entry and rules for a given mark
*/
static bool remove_entry(private_forecast_listener_t *this,
struct iptc_handle *ipth, child_sa_t *child_sa)
{
enumerator_t *enumerator;
entry_t *entry;
bool done = FALSE;
this->lock->write_lock(this->lock);
enumerator = this->entries->create_enumerator(this->entries);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->mark == child_sa->get_mark(child_sa, TRUE).value)
{
this->entries->remove_at(this->entries, enumerator);
if (manage_pre(ipth, entry, FALSE) &&
manage_out(ipth, entry, FALSE))
{
done = TRUE;
}
entry_destroy(entry);
break;
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
return done;
}
/**
* Initialize iptables handle, log error
*/
static struct iptc_handle* init_handle()
{
struct iptc_handle *ipth;
ipth = iptc_init("mangle");
if (ipth)
{
return ipth;
}
DBG1(DBG_CFG, "initializing iptables failed: %s", iptc_strerror(errno));
return NULL;
}
/**
* Commit iptables rules, log error
*/
static bool commit_handle(struct iptc_handle *ipth)
{
if (iptc_commit(ipth))
{
return TRUE;
}
DBG1(DBG_CFG, "forecast iptables commit failed: %s", iptc_strerror(errno));
return FALSE;
}
/**
* Check if we should handle the given CHILD_SA
*/
static bool handle_sa(child_sa_t *child_sa)
{
return child_sa->get_mark(child_sa, TRUE).value &&
child_sa->get_mark(child_sa, FALSE).value;
}
METHOD(listener_t, child_updown, bool,
private_forecast_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
bool up)
{
struct iptc_handle *ipth;
host_t *lhost, *rhost;
bool encap;
lhost = ike_sa->get_my_host(ike_sa);
rhost = ike_sa->get_other_host(ike_sa);
encap = child_sa->has_encap(child_sa);
if (handle_sa(child_sa))
{
ipth = init_handle();
if (ipth)
{
if (up)
{
if (add_entry(this, ipth, lhost, rhost, child_sa, encap))
{
commit_handle(ipth);
}
}
else
{
if (remove_entry(this, ipth, child_sa))
{
commit_handle(ipth);
}
}
iptc_free(ipth);
}
}
return TRUE;
}
METHOD(listener_t, child_rekey, bool,
private_forecast_listener_t *this, ike_sa_t *ike_sa,
child_sa_t *old, child_sa_t *new)
{
struct iptc_handle *ipth;;
host_t *lhost, *rhost;
lhost = ike_sa->get_my_host(ike_sa);
rhost = ike_sa->get_other_host(ike_sa);
if (handle_sa(old))
{
ipth = init_handle();
if (ipth)
{
if (remove_entry(this, ipth, old) &&
add_entry(this, ipth, lhost, rhost, new, new->has_encap(new)))
{
commit_handle(ipth);
}
iptc_free(ipth);
}
}
return TRUE;
}
METHOD(listener_t, ike_update, bool,
private_forecast_listener_t *this, ike_sa_t *ike_sa,
bool local, host_t *new)
{
struct iptc_handle *ipth;
enumerator_t *enumerator;
child_sa_t *child_sa;
host_t *lhost, *rhost;
bool encap;
if (local)
{
lhost = new;
rhost = ike_sa->get_other_host(ike_sa);
}
else
{
lhost = ike_sa->get_my_host(ike_sa);
rhost = new;
}
/* during ike_update(), has_encap() on the CHILD_SA has not yet been
* updated, but shows the old state. */
encap = ike_sa->has_condition(ike_sa, COND_NAT_ANY);
enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
while (enumerator->enumerate(enumerator, &child_sa))
{
if (handle_sa(child_sa))
{
ipth = init_handle();
if (ipth)
{
if (remove_entry(this, ipth, child_sa) &&
add_entry(this, ipth, lhost, rhost, child_sa, encap))
{
commit_handle(ipth);
}
iptc_free(ipth);
}
}
}
enumerator->destroy(enumerator);
return TRUE;
}
/**
* Filter to map entries to ts/mark
*/
static bool ts_filter(entry_t *entry, traffic_selector_t **ts,
traffic_selector_t **out, void *dummy, u_int32_t *mark,
void *dummy2, bool *reinject)
{
*out = *ts;
*mark = entry->mark;
*reinject = entry->reinject;
return TRUE;
}
/**
* Create inner enumerator over local traffic selectors
*/
static enumerator_t* create_inner_local(entry_t *entry, rwlock_t *lock)
{
return enumerator_create_filter(array_create_enumerator(entry->lts),
(void*)ts_filter, entry, NULL);
}
/**
* Create inner enumerator over remote traffic selectors
*/
static enumerator_t* create_inner_remote(entry_t *entry, rwlock_t *lock)
{
return enumerator_create_filter(array_create_enumerator(entry->rts),
(void*)ts_filter, entry, NULL);
}
METHOD(forecast_listener_t, create_enumerator, enumerator_t*,
private_forecast_listener_t *this, bool local)
{
this->lock->read_lock(this->lock);
return enumerator_create_nested(
this->entries->create_enumerator(this->entries),
(void*)(local ? create_inner_local : create_inner_remote),
this->lock, (void*)this->lock->unlock);
}
METHOD(forecast_listener_t, set_broadcast, void,
private_forecast_listener_t *this, host_t *bcast)
{
if (bcast->get_family(bcast) == AF_INET)
{
struct sockaddr_in *in;
in = bcast->get_sockaddr(bcast);
this->broadcast = in->sin_addr.s_addr;
}
}
METHOD(forecast_listener_t, destroy, void,
private_forecast_listener_t *this)
{
this->entries->destroy(this->entries);
this->lock->destroy(this->lock);
free(this);
}
/**
* See header
*/
forecast_listener_t *forecast_listener_create()
{
private_forecast_listener_t *this;
INIT(this,
.public = {
.listener = {
.ike_update = _ike_update,
.child_updown = _child_updown,
.child_rekey = _child_rekey,
},
.create_enumerator = _create_enumerator,
.set_broadcast = _set_broadcast,
.destroy = _destroy,
},
.entries = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
.reinject_configs = lib->settings->get_str(lib->settings,
"%s.plugins.forecast.reinject", "", lib->ns),
);
return &this->public;
}
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2010-2014 Martin Willi
* Copyright (C) 2010-2014 revosec 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 forecast_listener forecast_listener
* @{ @ingroup forecast
*/
#ifndef FORECAST_LISTENER_H_
#define FORECAST_LISTENER_H_
#include <bus/listeners/listener.h>
typedef struct forecast_listener_t forecast_listener_t;
/**
* Listener to register the set of IPs we forward received multi/broadcasts to.
*/
struct forecast_listener_t {
/**
* Implements listener_t interface.
*/
listener_t listener;
/**
* Create an enumerator over active tunnels.
*
* The enumerator enumerates over local or remote traffic selectors,
* associated firewall marks and if decasulated packets should get
* reinjected into other tunnels.
*
* @param local TRUE to enumerate local, FALSE to enumerate remote TS
* @return enumerator over (traffic_selector_t*, u_int, bool)
*/
enumerator_t* (*create_enumerator)(forecast_listener_t *this, bool local);
/**
* Set the broadcast address of the LAN interface.
*
* @param bcast broadcast address
*/
void (*set_broadcast)(forecast_listener_t *this, host_t *bcast);
/**
* Destroy a forecast_listener_t.
*/
void (*destroy)(forecast_listener_t *this);
};
/**
* Create a forecast_listener instance.
*/
forecast_listener_t *forecast_listener_create();
#endif /** FORECAST_LISTENER_H_ @}*/
@@ -0,0 +1,118 @@
/*
* Copyright (C) 2010-2014 Martin Willi
* Copyright (C) 2010-2014 revosec 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.
*/
#include "forecast_plugin.h"
#include "forecast_listener.h"
#include "forecast_forwarder.h"
#include <daemon.h>
typedef struct private_forecast_plugin_t private_forecast_plugin_t;
/**
* Private data of forecast plugin
*/
struct private_forecast_plugin_t {
/**
* implements plugin interface
*/
forecast_plugin_t public;
/**
* Listener registering active tunnels
*/
forecast_listener_t *listener;
/**
* Broadcast/Multicast sniffer and forwarder
*/
forecast_forwarder_t *forwarder;
};
METHOD(plugin_t, get_name, char*,
private_forecast_plugin_t *this)
{
return "forecast";
}
/**
* Register plugin features
*/
static bool register_forecast(private_forecast_plugin_t *this,
plugin_feature_t *feature, bool reg, void *data)
{
if (reg)
{
this->forwarder = forecast_forwarder_create(this->listener);
if (!this->forwarder)
{
return FALSE;
}
charon->bus->add_listener(charon->bus, &this->listener->listener);
}
else
{
charon->bus->remove_listener(charon->bus, &this->listener->listener);
this->forwarder->destroy(this->forwarder);
}
return TRUE;
}
METHOD(plugin_t, get_features, int,
private_forecast_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_CALLBACK((plugin_feature_callback_t)register_forecast, NULL),
PLUGIN_PROVIDE(CUSTOM, "forecast"),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_forecast_plugin_t *this)
{
this->listener->destroy(this->listener);
free(this);
}
/**
* Plugin constructor
*/
plugin_t *forecast_plugin_create()
{
private_forecast_plugin_t *this;
if (!lib->caps->keep(lib->caps, CAP_NET_RAW))
{
DBG1(DBG_NET, "forecast plugin requires CAP_NET_RAW capability");
return NULL;
}
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.reload = (void*)return_false,
.destroy = _destroy,
},
},
.listener = forecast_listener_create(),
);
return &this->public.plugin;
}
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2010-2014 Martin Willi
* Copyright (C) 2010-2014 revosec 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 forecast forecast
* @ingroup cplugins
*
* @defgroup forecast_plugin forecast_plugin
* @{ @ingroup forecast
*/
#ifndef FORECAST_PLUGIN_H_
#define FORECAST_PLUGIN_H_
#include <plugins/plugin.h>
typedef struct forecast_plugin_t forecast_plugin_t;
/**
* Broadcast/Multicast forwarding plugin.
*/
struct forecast_plugin_t {
/**
* Implements plugin interface.
*/
plugin_t plugin;
};
#endif /** FORECAST_PLUGIN_H_ @}*/
@@ -71,6 +71,7 @@ CONFIG_OPTS = \
--enable-dhcp \
--enable-farp \
--enable-connmark \
--enable-forecast \
--enable-addrblock \
--enable-ctr \
--enable-ccm \
@@ -0,0 +1,8 @@
The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each to
gateway <b>moon</b> and request a <b>virtual IP</b>. <b>moon</b> negotiates
broadcast and multicast traffic selectors with the clients, and uses
<i>%unique</i> marks to avoid any policy conflicts. The enabled <i>forecast</i>
plugin on <b>moon</b> installs the required Netfilter rules to make use of these
policies, and additionally starts forwarding broadcast and multicast packets
between the clients.<br/>
To test forwarding, the hosts send multicast and broadcast ping messages.
+20
View File
@@ -0,0 +1,20 @@
carol::ipsec status 2> /dev/null::home.*ESTABLISHED.*[email protected].*moon.strongswan.org::YES
carol::ipsec status 2> /dev/null::home.*INSTALLED, TUNNEL::YES
dave:: ipsec status 2> /dev/null::home.*ESTABLISHED.*[email protected].*moon.strongswan.org::YES
dave:: ipsec status 2> /dev/null::home.*INSTALLED, TUNNEL::YES
moon:: ipsec status 2> /dev/null::rw.*ESTABLISHED.*moon.strongswan.org.*[email protected]::YES
moon:: ipsec status 2> /dev/null::rw.*ESTABLISHED.*moon.strongswan.org.*[email protected]::YES
moon:: ipsec status 2> /dev/null::rw.*INSTALLED, TUNNEL, reqid 1::YES
moon:: ipsec status 2> /dev/null::rw.*INSTALLED, TUNNEL, reqid 2::YES
alice::ping -W 1 -c 1 239.0.0.1 2>&1> /dev/null
carol::ping -W 1 -c 1 239.0.0.2 2>&1> /dev/null
dave::ping -W 1 -c 1 239.0.0.3 2>&1> /dev/null
carol::ping -W 1 -c 1 -b 10.1.255.255 2>&1> /dev/null
dave::ping -W 1 -c 1 -b 10.1.255.255 2>&1> /dev/null
moon::iptables -t mangle -L -n -v
carol::tcpdump::IP alice.strongswan.org > 239.0.0.1: ICMP echo request::YES
dave::tcpdump::IP alice.strongswan.org > 239.0.0.1: ICMP echo request::YES
carol::tcpdump::IP 10.1.0.130 > 239.0.0.3: ICMP echo request::YES
dave::tcpdump::IP 10.1.0.129 > 239.0.0.2: ICMP echo request::YES
carol::tcpdump::IP 10.1.0.130 > 10.1.255.255: ICMP echo request::YES
dave::tcpdump::IP 10.1.0.129 > 10.1.255.255: ICMP echo request::YES
@@ -0,0 +1,21 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
keyexchange=ikev2
conn home
left=PH_IP_CAROL
leftsourceip=%config
leftsubnet=0.0.0.0/0
leftcert=carolCert.pem
[email protected]
right=PH_IP_MOON
rightsubnet=0.0.0.0/0
[email protected]
auto=add
@@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown resolve
}
@@ -0,0 +1,21 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
keyexchange=ikev2
conn home
left=PH_IP_DAVE
leftsourceip=%config
leftsubnet=0.0.0.0/0
leftcert=daveCert.pem
[email protected]
right=PH_IP_MOON
rightsubnet=0.0.0.0/0
[email protected]
auto=add
@@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown resolve
}
@@ -0,0 +1,22 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
keyexchange=ikev2
conn rw
left=PH_IP_MOON
leftcert=moonCert.pem
[email protected]
leftsubnet=10.1.0.0/16,224.0.0.0/4
right=%any
rightid=*@strongswan.org
rightsourceip=10.1.0.128/26
rightsubnet=%dynamic,224.0.0.0/4,10.1.255.255
mark=%unique
auto=add
@@ -0,0 +1,16 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown attr forecast
syslog {
daemon {
net = 2
}
}
plugins {
forecast {
interface = eth1
reinject = rw
}
}
}
@@ -0,0 +1,6 @@
moon::ipsec stop
carol::ipsec stop
dave::ipsec stop
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
dave::iptables-restore < /etc/iptables.flush
+7
View File
@@ -0,0 +1,7 @@
carol::ipsec start
dave::ipsec start
moon::ipsec start
carol::sleep 2
carol::ipsec up home
dave::ipsec up home
carol::sleep 1
+21
View File
@@ -0,0 +1,21 @@
#!/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 carol winnetou dave"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w-d.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon carol dave"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol dave"