I would like to see strongSwan support IPv6 VPNs to Windows 7+ using the
default Windows client. This is possible with a plugin I wrote.

Can this plugin be considered for merging?

I posted about this last year:
https://lists.strongswan.org/pipermail/users/2015-April/007812.html

We have been using this in production flawlessly since then. We've
upgraded from Ubuntu 14.04 to 16.04 (strongSwan 5.1.2 to 5.3.5), and the
patch continues to work.

Here's the relevant bug and wiki link to it, which shows other people
are interested:
https://wiki.strongswan.org/issues/817
https://wiki.strongswan.org/projects/1/wiki/Windows7#IPv6

The key part is the plugin, as it is compiled. The scripts are easy for
the sysadmin to add.

If there's a concern over the link local traffic selectors possibly
conflicting with link local on physical interfaces, link_local_ts could
be shipped but not loaded by default.

If there are other concerns with this patch, I'm happy to work to
address them.

So, to recap, to provide IPv4 and IPv6, with default routes, to a
Windows 7 system using its built-in VPN client, you need:

A)
https://wiki.strongswan.org/projects/strongswan/wiki/Win7UserMultipleConfig
B) leftsubnet=0.0.0.0/0,::/0
C) In addition to IPv4, provide an IPv6 block in rightsubnet=.
D) leftupdown=/path/to/the/attached/_updown
   Adapt `service radvd reload` as necessary for your distro.
E) OPTIONAL: If using usernames & passwords, rightauth=eap-mschapv2
F) OPTIONAL: Depending on your iptables setup, leftfirewall=yes
G) Build the link_local_ts plugin from the patch I attached.
H) Install radvd and the attached /etc/radvd.conf.in with eth0 adjusted
   for your system. Run _updown once to generate /etc/radvd.conf.
I) OPTIONAL: If your VPN server needs router announcements for its IPv6
   connectivity, you may need to add some firewall rules or something to
   keep the system from hearing the local radvd.

-- 
Richard
interface eth0
{
   # This is necessary to send RAs at all.
   AdvSendAdvert on;

   # _updown manages the list of clients:
   #clients { };
};
#!/usr/bin/perl

use strict;
use warnings;

use File::Temp;

my $standard_updown_script="ipsec _updown";
my $exclude_ip = "";

# We only care about fe80::X/128 addresses.
my $peer_client = $ENV{"PLUTO_PEER_CLIENT"};
if (defined($peer_client))
{
    unless ($peer_client =~ /^(fe80:[:0-9a-f]+)\/128$/)
    {
        exec($standard_updown_script);
    }
    # Save just the IP, not the mask.
    $peer_client = $1;

    my $verb = $ENV{"PLUTO_VERB"};
    if ($verb eq "down-client-v6")
    {
        # This script is called *before* the ip xfrm policy is removed.  On a
        # down-client-v6 action, we take note of the IP address being removed,
        # so we can ignore it later.
        $exclude_ip = $peer_client;
    }
    elsif ($verb ne "up-client-v6")
    {
        exec($standard_updown_script);
    }
}
else
{
    # When this script is run directly, we rebuild /etc/radvd.conf, but skip
    # running the standard updown script.
    $standard_updown_script = "true";
}

my $clients = "";
open my $ip_xfrm, "ip xfrm policy|" or die $!;
while (<$ip_xfrm>)
{
    if (/ dst (fe80:[:0-9a-f]+)\/128/ &&
        $1 ne $exclude_ip)
    {
        $clients .= "$1; ";
    }
}
close($ip_xfrm);

$clients =~ s/ $//;

if (length($clients) > 0)
{
    $clients = "clients { $clients };"
}
else
{
    # radvd treats an empty clients block as a syntax error.  Without a clients
    # block, we need to specify "UnicastOnly on" to keep radvd from sending
    # multicast RAs.  We can't specify it unconditionally because that breaks
    # sending unsolicited RAs to the clients in the clients block.
    $clients = "UnicastOnly on;";
}

open my $radvd_conf, "</etc/radvd.conf.in" or die $!;
my $tempfile = File::Temp->new(UNLINK => 0, DIR => "/etc");
while (<$radvd_conf>)
{
    if (/^( *)#?clients( |$)/)
    {
        print $tempfile "$1$clients\n";
    }
    else
    {
        print $tempfile $_;
    }
}
close($radvd_conf);

if ($tempfile->close() &&
    chmod(0644, $tempfile->filename) &&
    rename($tempfile->filename, "/etc/radvd.conf"))
{
    system("service radvd reload > /dev/null");
}

# Run the standard script.
exec($standard_updown_script);
--- a/configure.ac
+++ b/configure.ac
@@ -260,6 +260,7 @@
 ARG_ENABL_SET([farp],           [enable ARP faking plugin that responds to ARP requests to peers virtual IP])
 ARG_ENABL_SET([ha],             [enable high availability cluster plugin.])
 ARG_ENABL_SET([led],            [enable plugin to control LEDs on IKEv2 activity using the Linux kernel LED subsystem.])
+ARG_ENABL_SET([link_local_ts],  [enables the plugin which adds traffic selectors for IPv6 link local addresses.])
 ARG_ENABL_SET([load-tester],    [enable load testing plugin for IKEv2 daemon.])
 ARG_ENABL_SET([lookip],         [enable fast virtual IP lookup and notification plugin.])
 ARG_ENABL_SET([maemo],          [enable Maemo specific plugin.])
@@ -1401,6 +1402,7 @@
 ADD_PLUGIN([uci],                  [c charon])
 ADD_PLUGIN([addrblock],            [c charon])
 ADD_PLUGIN([unity],                [c charon])
+ADD_PLUGIN([link_local_ts],        [c charon])
 
 AC_SUBST(charon_plugins)
 AC_SUBST(starter_plugins)
@@ -1565,6 +1567,7 @@
 AM_CONDITIONAL(USE_RESOLVE, test x$resolve = xtrue)
 AM_CONDITIONAL(USE_ATTR, test x$attr = xtrue)
 AM_CONDITIONAL(USE_ATTR_SQL, test x$attr_sql = xtrue)
+AM_CONDITIONAL(USE_LINK_LOCAL_TS, test x$link_local_ts = xtrue)
 
 #  hydra plugins
 # ---------------
@@ -1832,6 +1835,7 @@
 	src/libcharon/plugins/android_dns/Makefile
 	src/libcharon/plugins/android_log/Makefile
 	src/libcharon/plugins/maemo/Makefile
+	src/libcharon/plugins/link_local_ts/Makefile
 	src/libcharon/plugins/stroke/Makefile
 	src/libcharon/plugins/vici/Makefile
 	src/libcharon/plugins/vici/ruby/Makefile
--- /dev/null
+++ b/src/libcharon/plugins/link_local_ts/link_local_ts_narrow.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 Wikstrom Telephone Company, Inc.
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ * Copyright (C) 2009 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "link_local_ts_narrow.h"
+
+#include <daemon.h>
+
+typedef struct private_link_local_ts_narrow_t private_link_local_ts_narrow_t;
+
+/**
+ * Private data of an link_local_ts_narrow_t object.
+ */
+struct private_link_local_ts_narrow_t {
+
+	/**
+	 * Public link_local_ts_narrow_t interface.
+	 */
+	link_local_ts_narrow_t public;
+};
+
+METHOD(listener_t, narrow, bool,
+	private_link_local_ts_narrow_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+	narrow_hook_t type, linked_list_t *local, linked_list_t *remote)
+{
+    chunk_t ll_chunk;
+    uint8_t ll_addr[16] = {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    enumerator_t *enumerator;
+    traffic_selector_t *ts;
+
+    if (type != NARROW_RESPONDER)
+    {
+        return TRUE;
+    }
+
+    ll_chunk.ptr = ll_addr;
+    ll_chunk.len = 16;
+
+    enumerator = remote->create_enumerator(remote);
+    while (enumerator->enumerate(enumerator, &ts))
+    {
+        chunk_t addr_chunk;
+        traffic_selector_t *ll_ts;
+        enumerator_t *enumerator2;
+        traffic_selector_t *ts2;
+
+        if (ts->get_type(ts) != TS_IPV6_ADDR_RANGE ||
+            ts->is_dynamic(ts) ||
+            !ts->is_host(ts, NULL) ||
+            ts->get_from_port(ts) != 0 ||
+            ts->get_to_port(ts) != 0xffff ||
+            ts->get_protocol(ts) != 0)
+        {
+            continue;
+        }
+
+        addr_chunk = ts->get_from_address(ts);
+        /* Copy the last 64-bits */
+        memcpy(ll_addr + 8, addr_chunk.ptr + 8, addr_chunk.len - 8);
+
+        ll_ts = traffic_selector_create_from_bytes(0, TS_IPV6_ADDR_RANGE, ll_chunk, 0, ll_chunk, 0xffff);
+
+        enumerator2 = remote->create_enumerator(remote);
+        while (enumerator2->enumerate(enumerator2, &ts2))
+        {
+            if (ll_ts->is_contained_in(ll_ts, ts2))
+            {
+                ll_ts->destroy(ll_ts);
+                goto continue_outer_loop;
+            }
+        }
+        enumerator2->destroy(enumerator2);
+
+        remote->insert_first(remote, ll_ts);
+
+continue_outer_loop: ;
+    }
+    enumerator->destroy(enumerator);
+
+	return TRUE;
+}
+
+METHOD(link_local_ts_narrow_t, destroy, void,
+	private_link_local_ts_narrow_t *this)
+{
+	free(this);
+}
+
+/**
+ * See header
+ */
+link_local_ts_narrow_t *link_local_ts_narrow_create()
+{
+	private_link_local_ts_narrow_t *this;
+
+	INIT(this,
+		.public = {
+			.listener.narrow = _narrow,
+			.destroy = _destroy,
+		},
+	);
+
+	return &this->public;
+}
--- /dev/null
+++ b/src/libcharon/plugins/link_local_ts/link_local_ts_narrow.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 link_local_ts_narrow link_local_ts_narrow
+ * @{ @ingroup link_local_ts
+ */
+
+#ifndef LINK_LOCAL_TS_NARROW_H_
+#define LINK_LOCAL_TS_NARROW_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct link_local_ts_narrow_t link_local_ts_narrow_t;
+
+/**
+ * Listener that adds traffic selectors for link local addresses corresponding
+ * to existing /128 traffic selectors
+ */
+struct link_local_ts_narrow_t {
+
+	/**
+	 * Implements listener_t.
+	 */
+	listener_t listener;
+
+	/**
+	 * Destroy a link_local_ts_narrow_t.
+	 */
+	void (*destroy)(link_local_ts_narrow_t *this);
+};
+
+/**
+ * Create a link_local_ts_narrow instance.
+ */
+link_local_ts_narrow_t *link_local_ts_narrow_create();
+
+#endif /** LINK_LOCAL_TS_NARROW_H_ @}*/
--- /dev/null
+++ b/src/libcharon/plugins/link_local_ts/link_local_ts_plugin.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "link_local_ts_plugin.h"
+
+#include <daemon.h>
+#include <plugins/plugin_feature.h>
+
+#include "link_local_ts_narrow.h"
+
+typedef struct private_link_local_ts_plugin_t private_link_local_ts_plugin_t;
+
+/**
+ * private data of link_local_ts_plugin
+ */
+struct private_link_local_ts_plugin_t {
+
+	/**
+	 * public functions
+	 */
+	link_local_ts_plugin_t public;
+
+	/**
+	 * Listener to check TS list
+	 */
+	link_local_ts_narrow_t *narrower;
+};
+
+METHOD(plugin_t, get_name, char*,
+	private_link_local_ts_plugin_t *this)
+{
+	return "link_local_ts";
+}
+
+/**
+ * Register listener
+ */
+static bool plugin_cb(private_link_local_ts_plugin_t *this,
+					  plugin_feature_t *feature, bool reg, void *cb_data)
+{
+	if (reg)
+	{
+		charon->bus->add_listener(charon->bus, &this->narrower->listener);
+	}
+	else
+	{
+		charon->bus->remove_listener(charon->bus, &this->narrower->listener);
+	}
+	return TRUE;
+}
+
+METHOD(plugin_t, get_features, int,
+	private_link_local_ts_plugin_t *this, plugin_feature_t *features[])
+{
+	static plugin_feature_t f[] = {
+		PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
+			PLUGIN_PROVIDE(CUSTOM, "link_local_ts"),
+				PLUGIN_SDEPEND(CERT_DECODE, CERT_X509),
+	};
+	*features = f;
+	return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+	private_link_local_ts_plugin_t *this)
+{
+	this->narrower->destroy(this->narrower);
+	free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *link_local_ts_plugin_create()
+{
+	private_link_local_ts_plugin_t *this;
+
+	INIT(this,
+		.public = {
+			.plugin = {
+				.get_name = _get_name,
+				.get_features = _get_features,
+				.destroy = _destroy,
+			},
+		},
+		.narrower = link_local_ts_narrow_create(),
+	);
+
+	return &this->public.plugin;
+}
--- /dev/null
+++ b/src/libcharon/plugins/link_local_ts/link_local_ts_plugin.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 link_local_ts link_local_ts
+ * @ingroup cplugins
+ *
+ * @defgroup link_local_ts_plugin link_local_ts_plugin
+ * @{ @ingroup link_local_ts
+ */
+
+#ifndef LINK_LOCAL_TS_PLUGIN_H_
+#define LINK_LOCAL_TS_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct link_local_ts_plugin_t link_local_ts_plugin_t;
+
+/**
+ * Plugin that adds traffic selectors for link local addresses corresponding
+ * to existing /128 traffic selectors
+ */
+struct link_local_ts_plugin_t {
+
+	/**
+	 * Implements plugin_t. interface.
+	 */
+	plugin_t plugin;
+};
+
+#endif /** LINK_LOCAL_TS_PLUGIN_H_ @}*/
--- /dev/null
+++ b/src/libcharon/plugins/link_local_ts/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/src/libstrongswan \
+	-I$(top_srcdir)/src/libhydra \
+	-I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = \
+	-rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-link_local_ts.la
+else
+plugin_LTLIBRARIES = libstrongswan-link_local_ts.la
+endif
+
+libstrongswan_link_local_ts_la_SOURCES = \
+	link_local_ts_plugin.h link_local_ts_plugin.c \
+	link_local_ts_narrow.h link_local_ts_narrow.c
+
+libstrongswan_link_local_ts_la_LDFLAGS = -module -avoid-version
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -609,6 +609,13 @@
 endif
 endif
 
+if USE_LINK_LOCAL_TS
+  SUBDIRS += plugins/link_local_ts
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/link_local_ts/libstrongswan-link_local_ts.la
+endif
+endif
+
 if USE_UNITY
   SUBDIRS += plugins/unity
 if MONOLITHIC
_______________________________________________
Dev mailing list
[email protected]
https://lists.strongswan.org/mailman/listinfo/dev

Reply via email to