summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/vici
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2016-03-24 11:59:32 +0100
committerYves-Alexis Perez <corsac@debian.org>2016-03-24 11:59:32 +0100
commit518dd33c94e041db0444c7d1f33da363bb8e3faf (patch)
treee8d1665ffadff7ec40228dda47e81f8f4691cd07 /src/libcharon/plugins/vici
parentf42f239a632306ed082f6fde878977248eea85cf (diff)
downloadvyos-strongswan-518dd33c94e041db0444c7d1f33da363bb8e3faf.tar.gz
vyos-strongswan-518dd33c94e041db0444c7d1f33da363bb8e3faf.zip
Imported Upstream version 5.4.0
Diffstat (limited to 'src/libcharon/plugins/vici')
-rw-r--r--src/libcharon/plugins/vici/Makefile.am8
-rw-r--r--src/libcharon/plugins/vici/Makefile.in22
-rw-r--r--src/libcharon/plugins/vici/README.md98
-rw-r--r--src/libcharon/plugins/vici/perl/Makefile.am27
-rw-r--r--src/libcharon/plugins/vici/perl/Makefile.in567
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/Changes6
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/MANIFEST9
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/Makefile.PL11
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/README.pod649
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Message.pm256
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Packet.pm191
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Session.pm204
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Transport.pm88
-rw-r--r--src/libcharon/plugins/vici/perl/Vici-Session/t/Vici-Session.t18
-rw-r--r--src/libcharon/plugins/vici/python/Makefile.in2
-rw-r--r--src/libcharon/plugins/vici/python/vici/session.py8
-rw-r--r--src/libcharon/plugins/vici/ruby/Makefile.in2
-rw-r--r--src/libcharon/plugins/vici/ruby/lib/vici.rb6
-rw-r--r--src/libcharon/plugins/vici/vici_cert_info.c57
-rw-r--r--src/libcharon/plugins/vici/vici_cert_info.h32
-rw-r--r--src/libcharon/plugins/vici/vici_config.c359
-rw-r--r--src/libcharon/plugins/vici/vici_config.h5
-rw-r--r--src/libcharon/plugins/vici/vici_control.c187
-rw-r--r--src/libcharon/plugins/vici/vici_cred.c69
-rw-r--r--src/libcharon/plugins/vici/vici_plugin.c3
-rw-r--r--src/libcharon/plugins/vici/vici_query.c374
-rw-r--r--src/libcharon/plugins/vici/vici_tests.c1
27 files changed, 3043 insertions, 216 deletions
diff --git a/src/libcharon/plugins/vici/Makefile.am b/src/libcharon/plugins/vici/Makefile.am
index c99d23e4e..ca9b49906 100644
--- a/src/libcharon/plugins/vici/Makefile.am
+++ b/src/libcharon/plugins/vici/Makefile.am
@@ -1,6 +1,6 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
- -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libstrongswan/plugins/pubkey \
-I$(top_srcdir)/src/libcharon \
-DIPSEC_PIDDIR=\"${piddir}\"
@@ -18,6 +18,7 @@ libstrongswan_vici_la_SOURCES = \
vici_message.h vici_message.c \
vici_builder.h vici_builder.c \
vici_dispatcher.h vici_dispatcher.c \
+ vici_cert_info.h vici_cert_info.c \
vici_query.h vici_query.c \
vici_control.h vici_control.c \
vici_config.h vici_config.c \
@@ -38,6 +39,7 @@ ipseclib_LTLIBRARIES = libvici.la
libvici_la_SOURCES = \
vici_message.c vici_message.h \
vici_builder.c vici_builder.h \
+ vici_cert_info.h vici_cert_info.c \
libvici.c libvici.h
libvici_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
@@ -79,3 +81,7 @@ endif
if USE_PYTHON_EGGS
SUBDIRS += python
endif
+
+if USE_PERL_CPAN
+SUBDIRS += perl
+endif
diff --git a/src/libcharon/plugins/vici/Makefile.in b/src/libcharon/plugins/vici/Makefile.in
index 1a7870ae9..86ed00792 100644
--- a/src/libcharon/plugins/vici/Makefile.in
+++ b/src/libcharon/plugins/vici/Makefile.in
@@ -82,6 +82,7 @@ TESTS = vici_tests$(EXEEXT)
check_PROGRAMS = $(am__EXEEXT_1)
@USE_RUBY_GEMS_TRUE@am__append_1 = ruby
@USE_PYTHON_EGGS_TRUE@am__append_2 = python
+@USE_PERL_CPAN_TRUE@am__append_3 = perl
subdir = src/libcharon/plugins/vici
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/depcomp
@@ -134,9 +135,10 @@ LTLIBRARIES = $(ipseclib_LTLIBRARIES) $(noinst_LTLIBRARIES) \
$(plugin_LTLIBRARIES)
libstrongswan_vici_la_LIBADD =
am_libstrongswan_vici_la_OBJECTS = vici_socket.lo vici_message.lo \
- vici_builder.lo vici_dispatcher.lo vici_query.lo \
- vici_control.lo vici_config.lo vici_cred.lo vici_attribute.lo \
- vici_authority.lo vici_logger.lo vici_plugin.lo
+ vici_builder.lo vici_dispatcher.lo vici_cert_info.lo \
+ vici_query.lo vici_control.lo vici_config.lo vici_cred.lo \
+ vici_attribute.lo vici_authority.lo vici_logger.lo \
+ vici_plugin.lo
libstrongswan_vici_la_OBJECTS = $(am_libstrongswan_vici_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -150,7 +152,8 @@ libstrongswan_vici_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
@MONOLITHIC_TRUE@am_libstrongswan_vici_la_rpath =
libvici_la_DEPENDENCIES = \
$(top_builddir)/src/libstrongswan/libstrongswan.la
-am_libvici_la_OBJECTS = vici_message.lo vici_builder.lo libvici.lo
+am_libvici_la_OBJECTS = vici_message.lo vici_builder.lo \
+ vici_cert_info.lo libvici.lo
libvici_la_OBJECTS = $(am_libvici_la_OBJECTS)
am__EXEEXT_1 = vici_tests$(EXEEXT)
am__dirstamp = $(am__leading_dot)dirstamp
@@ -270,7 +273,7 @@ am__tty_colors = { \
std=''; \
fi; \
}
-DIST_SUBDIRS = ruby python
+DIST_SUBDIRS = ruby python perl
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
@@ -509,6 +512,8 @@ strongswan_conf = @strongswan_conf@
strongswan_options = @strongswan_options@
swanctldir = @swanctldir@
sysconfdir = @sysconfdir@
+systemd_CFLAGS = @systemd_CFLAGS@
+systemd_LIBS = @systemd_LIBS@
systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@
systemd_daemon_LIBS = @systemd_daemon_LIBS@
systemd_journal_CFLAGS = @systemd_journal_CFLAGS@
@@ -524,7 +529,7 @@ xml_CFLAGS = @xml_CFLAGS@
xml_LIBS = @xml_LIBS@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
- -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libstrongswan/plugins/pubkey \
-I$(top_srcdir)/src/libcharon \
-DIPSEC_PIDDIR=\"${piddir}\"
@@ -538,6 +543,7 @@ libstrongswan_vici_la_SOURCES = \
vici_message.h vici_message.c \
vici_builder.h vici_builder.c \
vici_dispatcher.h vici_dispatcher.c \
+ vici_cert_info.h vici_cert_info.c \
vici_query.h vici_query.c \
vici_control.h vici_control.c \
vici_config.h vici_config.c \
@@ -553,6 +559,7 @@ ipseclib_LTLIBRARIES = libvici.la
libvici_la_SOURCES = \
vici_message.c vici_message.h \
vici_builder.c vici_builder.h \
+ vici_cert_info.h vici_cert_info.c \
libvici.c libvici.h
libvici_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
@@ -578,7 +585,7 @@ vici_tests_LDADD = \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(top_builddir)/src/libstrongswan/tests/libtest.la
-SUBDIRS = $(am__append_1) $(am__append_2)
+SUBDIRS = $(am__append_1) $(am__append_2) $(am__append_3)
all: all-recursive
.SUFFIXES:
@@ -739,6 +746,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_attribute.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_authority.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_builder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_cert_info.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_config.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_control.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_cred.Plo@am__quote@
diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
index b9531d8a5..52929bd74 100644
--- a/src/libcharon/plugins/vici/README.md
+++ b/src/libcharon/plugins/vici/README.md
@@ -258,7 +258,8 @@ Initiates an SA while streaming _control-log_ events.
{
child = <CHILD_SA configuration name to initiate>
- timeout = <timeout in seconds before returning>
+ ike = <optional IKE_SA configuraiton name to find child under>
+ timeout = <timeout in ms before returning>
init-limits = <whether limits may prevent initiating the CHILD_SA>
loglevel = <loglevel to issue "control-log" events for>
} => {
@@ -266,6 +267,9 @@ Initiates an SA while streaming _control-log_ events.
errmsg = <error string on failure or timeout>
}
+The default timeout of 0 waits indefinitely for a result, and a timeout value
+of -1 returns a result immediately.
+
### terminate() ###
Terminates an SA while streaming _control-log_ events.
@@ -275,19 +279,40 @@ Terminates an SA while streaming _control-log_ events.
ike = <terminate an IKE_SA by configuration name>
child_id = <terminate a CHILD_SA by its reqid>
ike_id = <terminate an IKE_SA by its unique id>
- timeout = <timeout in seconds before returning>
+ timeout = <timeout in ms before returning>
loglevel = <loglevel to issue "control-log" events for>
} => {
success = <yes or no>
errmsg = <error string on failure or timeout>
}
+The default timeout of 0 waits indefinitely for a result, and a timeout value
+of -1 returns a result immediately.
+
+### redirect() ###
+
+Redirect a client-initiated IKE_SA to another gateway. Only for IKEv2 and if
+supported by the peer.
+
+ {
+ ike = <redirect an IKE_SA by configuration name>
+ ike-id = <redirect an IKE_SA by its unique id>
+ peer-ip = <redirect an IKE_SA with matching peer IP, may also be a
+ subnet in CIDR notation or an IP range>
+ peer-id = <redirect an IKE_SA with matching peer identity, may contain
+ wildcards>
+ } => {
+ success = <yes or no>
+ errmsg = <error string on failure>
+ }
+
### install() ###
Install a trap, drop or bypass policy defined by a CHILD_SA config.
{
child = <CHILD_SA configuration name to install>
+ ike = <optional IKE_SA configuraiton name to find child under>
} => {
success = <yes or no>
errmsg = <error string on failure>
@@ -361,7 +386,9 @@ call includes all certificates known by the daemon, not only those loaded
over vici.
{
- type = <certificate type to filter for, or ANY>
+ type = <certificate type to filter for, X509|X509_AC|X509_CRL|
+ OCSP_RESPONSE|PUBKEY or ANY>
+ flag = <X.509 certificate flag to filter for, NONE|CA|AA|OCSP or ANY>
subject = <set to list only certificates having subject>
} => {
# completes after streaming list-cert events
@@ -419,7 +446,8 @@ Unload a previously loaded connection definition by name.
Load a certificate into the daemon.
{
- type = <certificate type, X509|X509CA|X509AA|X509CRL|X509AC>
+ type = <certificate type, X509|X509_AC|X509_CRL>
+ flag = <X.509 certificate flag, NONE|CA|AA|OCSP>
data = <PEM or DER encoded certificate data>
} => {
success = <yes or no>
@@ -544,6 +572,16 @@ List the currently loaded pools.
}
}
+### get-algorithms() ###
+
+List currently loaded algorithms and their implementation.
+
+ {} => {
+ <algorithm type> = {
+ <algorithm> = <plugin providing the implementation>
+ }
+ }
+
## Server-issued events ##
Based on the packet layer, the vici plugin raises event messages using named
@@ -588,8 +626,10 @@ command.
version = <IKE version, 1 or 2>
state = <IKE_SA state name>
local-host = <local IKE endpoint address>
+ local-port = <local IKE endpoint port>
local-id = <local IKE identity>
remote-host = <remote IKE endpoint address>
+ remote-port = <remote IKE endpoint port>
remote-id = <remote IKE identity>
remote-xauth-id = <remote XAuth identity, if XAuth-authenticated>
remote-eap-id = <remote EAP identity, if EAP-authenticated>
@@ -735,9 +775,13 @@ The _list-cert_ event is issued to stream loaded certificates during an active
_list-certs_ command.
{
- type = <certificate type>
+ type = <certificate type, X509|X509_AC|X509_CRL|OCSP_RESPONSE|PUBKEY>
+ flag = <X.509 certificate flag, NONE|CA|AA|OCSP>
has_privkey = <set if a private key for the certificate is available>
data = <ASN1 encoded certificate data>
+ subject = <subject string if defined and certificate type is PUBKEY>
+ not-before = <time string if defined and certificate type is PUBKEY>
+ not-after = <time string if defined and certificate type is PUBKEY>
}
### list-authority ###
@@ -763,7 +807,7 @@ information during an active_list-authorities_ command.
The _ike-updown_ event is issued when an IKE_SA is established or terminated.
{
- up = <yes or no>
+ up = <set if up event>
<IKE_SA config name> = {
<same data as in the list-sas event, but without child-sas section>
}
@@ -789,7 +833,7 @@ The _ike-rekey_ event is issued when an IKE_SA is rekeyed.
The _child-updown_ event is issued when a CHILD_SA is established or terminated.
{
- up = <yes or no>
+ up = <set if up event>
<IKE_SA config name> = {
<same data as in the list-sas event, but with only the affected
CHILD_SA in the child-sas section>
@@ -1068,3 +1112,43 @@ dictionaries. Objects returned by the library use OrderedDicts.
For more details about the Python egg refer to the comments in the Python source
code.
+
+# Vici::Session Perl CPAN module #
+
+The _Vici::Session Perl CPAN module_ is a pure Perl implementation of the VICI
+protocol to implement client applications. It is provided in the _perl_
+subdirectory, and gets built and installed if strongSwan has been
+ _./configure_'d with_--enable-vici_ and _--enable-perl-cpan_.
+
+The _Vici::Session_ module provides a _new()_ constructor for a high level
+interface, the underlying _Vici::Packet_ and _Vici::Transport_ classes are
+usually not required to build Perl applications using VICI. The _Vici::Session_
+class provides methods for the supported VICI commands. The auxiliare
+ _Vici::Message_ class is used to encode configuration parameters sent to
+the daemon and decode data returned by the daemon.
+
+## Connecting to the daemon ##
+
+ use IO::Socket::UNIX;
+ use Vici::Session;
+ use Vici::Message;
+
+ my $socket = IO::Socket::UNIX->new(
+ Type => SOCK_STREAM,
+ Peer => '/var/run/charon.vici',
+ ) or die "Vici socket: $!";
+
+ my $session = Vici::Session->new($socket);
+
+## A simple client request ##
+
+An example to print the daemon version information is as simple as:
+
+ my $version = $session->version()->hash();
+
+ foreach my $key ('daemon', 'version', 'sysname', 'release', 'machine' ) {
+ print $version->{$key}, " ";
+ }
+
+The _Vici::Session_ methods are explained in the perl/Vici-Session/README.pod
+document.
diff --git a/src/libcharon/plugins/vici/perl/Makefile.am b/src/libcharon/plugins/vici/perl/Makefile.am
new file mode 100644
index 000000000..9bc6262ac
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Makefile.am
@@ -0,0 +1,27 @@
+EXTRA_DIST = \
+ Vici-Session/Changes \
+ Vici-Session/Makefile.PL \
+ Vici-Session/MANIFEST \
+ Vici-Session/README.pod \
+ Vici-Session/t/Vici-Session.t \
+ Vici-Session/lib/Vici/Message.pm \
+ Vici-Session/lib/Vici/Packet.pm \
+ Vici-Session/lib/Vici/Session.pm \
+ Vici-Session/lib/Vici/Transport.pm
+
+all-local: Vici-Session/pm_to_blib
+
+Vici-Session/Makefile: $(srcdir)/Vici-Session/Makefile.PL
+ (cd $(srcdir)/Vici-Session; $(PERL) Makefile.PL)
+
+Vici-Session/pm_to_blib: $(EXTRA_DIST) $(srcdir)/Vici-Session/Makefile
+ (cd $(srcdir)/Vici-Session; make)
+
+clean-local:
+ (cd $(srcdir)/Vici-Session; [ ! -f Makefile ] || make clean)
+
+if PERL_CPAN_INSTALL
+install-exec-local: Vici-Session/pm_to_blib
+ (cd $(srcdir)/Vici-Session; make install)
+endif
+
diff --git a/src/libcharon/plugins/vici/perl/Makefile.in b/src/libcharon/plugins/vici/perl/Makefile.in
new file mode 100644
index 000000000..550d3e980
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Makefile.in
@@ -0,0 +1,567 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libcharon/plugins/vici/perl
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
+ $(top_srcdir)/m4/config/ltoptions.m4 \
+ $(top_srcdir)/m4/config/ltsugar.m4 \
+ $(top_srcdir)/m4/config/ltversion.m4 \
+ $(top_srcdir)/m4/config/lt~obsolete.m4 \
+ $(top_srcdir)/m4/macros/split-package-version.m4 \
+ $(top_srcdir)/m4/macros/with.m4 \
+ $(top_srcdir)/m4/macros/enable-disable.m4 \
+ $(top_srcdir)/m4/macros/add-plugin.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BFDLIB = @BFDLIB@
+BTLIB = @BTLIB@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COVERAGE_CFLAGS = @COVERAGE_CFLAGS@
+COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLIB = @DLLIB@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+EASY_INSTALL = @EASY_INSTALL@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEM = @GEM@
+GENHTML = @GENHTML@
+GPERF = @GPERF@
+GPRBUILD = @GPRBUILD@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQLCFLAG = @MYSQLCFLAG@
+MYSQLCONFIG = @MYSQLCONFIG@
+MYSQLLIB = @MYSQLLIB@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_LIB = @OPENSSL_LIB@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_BUILD = @PACKAGE_VERSION_BUILD@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_REVIEW = @PACKAGE_VERSION_REVIEW@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PLUGIN_CFLAGS = @PLUGIN_CFLAGS@
+PTHREADLIB = @PTHREADLIB@
+PYTHON = @PYTHON@
+PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_TEST = @PY_TEST@
+RANLIB = @RANLIB@
+RTLIB = @RTLIB@
+RUBY = @RUBY@
+RUBYGEMDIR = @RUBYGEMDIR@
+RUBYINCLUDE = @RUBYINCLUDE@
+RUBYLIB = @RUBYLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKLIB = @SOCKLIB@
+STRIP = @STRIP@
+UNWINDLIB = @UNWINDLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+aikgen_plugins = @aikgen_plugins@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_plugins = @c_plugins@
+charon_natt_port = @charon_natt_port@
+charon_plugins = @charon_plugins@
+charon_udp_port = @charon_udp_port@
+clearsilver_LIBS = @clearsilver_LIBS@
+cmd_plugins = @cmd_plugins@
+datadir = @datadir@
+datarootdir = @datarootdir@
+dbusservicedir = @dbusservicedir@
+dev_headers = @dev_headers@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+fips_mode = @fips_mode@
+gtk_CFLAGS = @gtk_CFLAGS@
+gtk_LIBS = @gtk_LIBS@
+h_plugins = @h_plugins@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+imcvdir = @imcvdir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsec_script = @ipsec_script@
+ipsec_script_upper = @ipsec_script_upper@
+ipsecdir = @ipsecdir@
+ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
+ipsecuser = @ipsecuser@
+json_CFLAGS = @json_CFLAGS@
+json_LIBS = @json_LIBS@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libiptc_CFLAGS = @libiptc_CFLAGS@
+libiptc_LIBS = @libiptc_LIBS@
+linux_headers = @linux_headers@
+localedir = @localedir@
+localstatedir = @localstatedir@
+maemo_CFLAGS = @maemo_CFLAGS@
+maemo_LIBS = @maemo_LIBS@
+manager_plugins = @manager_plugins@
+mandir = @mandir@
+medsrv_plugins = @medsrv_plugins@
+mkdir_p = @mkdir_p@
+nm_CFLAGS = @nm_CFLAGS@
+nm_LIBS = @nm_LIBS@
+nm_ca_dir = @nm_ca_dir@
+nm_plugins = @nm_plugins@
+oldincludedir = @oldincludedir@
+pcsclite_CFLAGS = @pcsclite_CFLAGS@
+pcsclite_LIBS = @pcsclite_LIBS@
+pdfdir = @pdfdir@
+piddir = @piddir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+pki_plugins = @pki_plugins@
+plugindir = @plugindir@
+pool_plugins = @pool_plugins@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+random_device = @random_device@
+resolv_conf = @resolv_conf@
+routing_table = @routing_table@
+routing_table_prio = @routing_table_prio@
+s_plugins = @s_plugins@
+sbindir = @sbindir@
+scepclient_plugins = @scepclient_plugins@
+scripts_plugins = @scripts_plugins@
+sharedstatedir = @sharedstatedir@
+soup_CFLAGS = @soup_CFLAGS@
+soup_LIBS = @soup_LIBS@
+srcdir = @srcdir@
+starter_plugins = @starter_plugins@
+strongswan_conf = @strongswan_conf@
+strongswan_options = @strongswan_options@
+swanctldir = @swanctldir@
+sysconfdir = @sysconfdir@
+systemd_CFLAGS = @systemd_CFLAGS@
+systemd_LIBS = @systemd_LIBS@
+systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@
+systemd_daemon_LIBS = @systemd_daemon_LIBS@
+systemd_journal_CFLAGS = @systemd_journal_CFLAGS@
+systemd_journal_LIBS = @systemd_journal_LIBS@
+systemdsystemunitdir = @systemdsystemunitdir@
+t_plugins = @t_plugins@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+urandom_device = @urandom_device@
+xml_CFLAGS = @xml_CFLAGS@
+xml_LIBS = @xml_LIBS@
+EXTRA_DIST = \
+ Vici-Session/Changes \
+ Vici-Session/Makefile.PL \
+ Vici-Session/MANIFEST \
+ Vici-Session/README.pod \
+ Vici-Session/t/Vici-Session.t \
+ Vici-Session/lib/Vici/Message.pm \
+ Vici-Session/lib/Vici/Packet.pm \
+ Vici-Session/lib/Vici/Session.pm \
+ Vici-Session/lib/Vici/Transport.pm
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/vici/perl/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libcharon/plugins/vici/perl/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile all-local
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+@PERL_CPAN_INSTALL_FALSE@install-exec-local:
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-exec-local
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+ clean-libtool clean-local cscopelist-am ctags-am distclean \
+ distclean-generic distclean-libtool distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-exec-local install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am
+
+
+all-local: Vici-Session/pm_to_blib
+
+Vici-Session/Makefile: $(srcdir)/Vici-Session/Makefile.PL
+ (cd $(srcdir)/Vici-Session; $(PERL) Makefile.PL)
+
+Vici-Session/pm_to_blib: $(EXTRA_DIST) $(srcdir)/Vici-Session/Makefile
+ (cd $(srcdir)/Vici-Session; make)
+
+clean-local:
+ (cd $(srcdir)/Vici-Session; [ ! -f Makefile ] || make clean)
+
+@PERL_CPAN_INSTALL_TRUE@install-exec-local: Vici-Session/pm_to_blib
+@PERL_CPAN_INSTALL_TRUE@ (cd $(srcdir)/Vici-Session; make install)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/Changes b/src/libcharon/plugins/vici/perl/Vici-Session/Changes
new file mode 100644
index 000000000..0c30328fd
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension Vici::Session.
+
+0.9 Tue Nov 17 11:45:21 2015
+ - original version; created by h2xs 1.23 with options
+ -X -n Vici::Session
+
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/MANIFEST b/src/libcharon/plugins/vici/perl/Vici-Session/MANIFEST
new file mode 100644
index 000000000..c19032a08
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/MANIFEST
@@ -0,0 +1,9 @@
+Changes
+Makefile.PL
+MANIFEST
+README.pod
+t/Vici-Session.t
+lib/Vici/Session.pm
+lib/Vici/Message.pm
+lib/Vici/Packet.pm
+lib/Vici/Transport.pm
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/Makefile.PL b/src/libcharon/plugins/vici/perl/Vici-Session/Makefile.PL
new file mode 100644
index 000000000..65f494557
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/Makefile.PL
@@ -0,0 +1,11 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ NAME => 'Vici::Session',
+ VERSION_FROM => 'lib/Vici/Session.pm', # finds $VERSION
+ PREREQ_PM => {}, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'lib/Vici/Session.pm', # retrieve abstract from module
+ AUTHOR => 'Andreas Steffen <andreas.steffen@>strongswan.org') : ()),
+);
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/README.pod b/src/libcharon/plugins/vici/perl/Vici-Session/README.pod
new file mode 100644
index 000000000..de374aa11
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/README.pod
@@ -0,0 +1,649 @@
+
+=head1 NAME
+
+Vici::Session - Perl binding for the strongSwan VICI configuration interface
+
+=head1 DESCRIPTION
+
+The Vici::Session module allows a Perl script to communicate with the open
+source strongSwan IPsec daemon (https://www.strongswan.org) via the documented
+Versatile IKE Configuration Interface (VICI). VICI allows the configuration,
+management and monitoring of multiple IPsec connections.
+
+=head1 INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make install
+
+=head1 DEPENDENCIES
+
+This module requires the standard networking module:
+
+ IO::Socket::UNIX
+
+=head1 METHODS
+
+The following examples show the use of the Vici::Session interface in a
+a "net-net" connection between the VPN gateways "moon" and "sun".
+
+=cut
+
+use strict;
+use warnings;
+use IO::Socket::UNIX;
+use Vici::Message;
+use Vici::Session;
+
+my $moon_key = "-----BEGIN RSA PRIVATE KEY-----\n" .
+ "MIIEowIBAAKCAQEApHwF+sUXQdH+WwYzdPMzpjuwhGGvHgsmBah1IQsPsddL9gZy" .
+ "gerzpTM1vvQ4kbRuvE3SZWLf9uKEbiQV9IABr87L9JAva56EHIAiUMuG8WizVbIK" .
+ "IhQlZc8S2mIwAW0Jc6EmnoJv9j6F/tVD9+6xvMJbwHLi0h7BUO9tBVLPy72YeGNB" .
+ "Y6Cob4CrOuFOJyACezJ7i9vZ+XzOfnXpu7qL0DgYP/n2maPEJGEivTFunkJD/mJ8" .
+ "DecyLTQcchsCj2118BMuf2qjVn4UWPCBBuhyYK5wsATB1ANeAtlFfgH+wsuHjZwt" .
+ "TJru05lGHBZ3F2hZ9PO68hVHbIZZj6SB8X47nwIDAQABAoIBAAQDXqX6rxGVDQ6t" .
+ "fQ3qbSUuKaVhOMOT5A6ZSJpQycY+CYVsLNkMoXszX6lUDhlH/Letcme03OAKMM77" .
+ "JGn9wYzHj+RcrDuE95Y2bh/oh1dWhaGeoW6pbSwpvD0FzkQKpANlOCr/5bltVxmb" .
+ "nHftI/sGBvUQGIal53ORE+jgV1+SK6I0oAIWiCpU2oZpYMAtp7WxOngsAJaGtk//" .
+ "m2ckH+T8uVHwe9gJ9HZnEk+Io6BXScMNNrsbd2J+pQ75wQXfzHEzHAj+ElhWzhtc" .
+ "5XefqHw/DfpPDX/lby3VoSoagqzsVuUx7LylgzIDxTsb9HQVOLjDzOQ+vn22Xj7g" .
+ "UCEjwLkCgYEA2EZguuzJdxRIWBSnIyzpCzfqm0EgybpeLuJVfzWla0yKWI6AeLhW" .
+ "cr+7o9UE8nCQHVffIrgjWksjc/S5FhzC9TYSHpPa8TPgebTQK4VxnP9Qkh/XRpJj" .
+ "CqgJ8k2MYleHYxa+AKQv/25yNhLdowkNR0iU1kbiaYRJMP0WigAmdAUCgYEAwrJe" .
+ "Y3LAawOkalJFMFTtLXsqZE91TFwMt9TQnzysGH3Q6+9N+qypS5KCes650+qgrwBV" .
+ "RmRNc1ixylToP3B0BKY5OD/BwMx1L/zSO3x7I4ZDasCu33y2ukGLcVSxrxTPTGdd" .
+ "8fhEiVO1CDXcM08/kSeQa049J8ziY3M+4NDchlMCgYEAw2VCO1923Tjb64gtQOBw" .
+ "ZAxOz5nVz6urL9yYted33is2yq9kbqzMnbuQAYKRh6Ae9APRuwJ2HjvIehjdp5aw" .
+ "pO4HDM00f7sI0ayEbu2PKfKZjotp6X6UMKqE4f8iGC9QSDvhyZ6NJs9YLHZ6+7NP" .
+ "5dkzbyx3njFAFxxxYpikJSkCgYByShB8YlUvvKCcRRUWbRQZWa6l2brqizJwCz43" .
+ "636+lcS5au2klAyBL0zm2Elfa+DNOe3U93Y7mrorIrJ+4v1H6We3bD3JdnvoIooq" .
+ "n0UNsngKx3cf++6r4WQAsA3pz9ZsbFVKgEmDL58aZbuQZxnSlJ4DT5c4sN3IMVOc" .
+ "1x5MvwKBgHudAaLvioIopBpYzOsK2OtEn6NQ7SwH0BLEUulHysaHqan5oExmM1bm" .
+ "YeivMDc9hj0YLXA47ryQHTx4vB5Nv3TI/LoUG6VrCvZvocQOXe/n7TguwAjJj7ef" .
+ "E55Gy8lXDRENyJMP1vif3N2iH8eQ1ASf8k/+gnBNkjSlYSSQUDfV\n" .
+ "-----END RSA PRIVATE KEY-----\n";
+
+my $moon_cert = "-----BEGIN CERTIFICATE-----\n" .
+ "MIIEIjCCAwqgAwIBAgIBKzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ" .
+ "MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS" .
+ "b290IENBMB4XDTE0MDgyNzE0NDQ1NloXDTE5MDgyNjE0NDQ1NlowRjELMAkGA1UE" .
+ "BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHDAaBgNVBAMTE21vb24u" .
+ "c3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCk" .
+ "fAX6xRdB0f5bBjN08zOmO7CEYa8eCyYFqHUhCw+x10v2BnKB6vOlMzW+9DiRtG68" .
+ "TdJlYt/24oRuJBX0gAGvzsv0kC9rnoQcgCJQy4bxaLNVsgoiFCVlzxLaYjABbQlz" .
+ "oSaegm/2PoX+1UP37rG8wlvAcuLSHsFQ720FUs/LvZh4Y0FjoKhvgKs64U4nIAJ7" .
+ "MnuL29n5fM5+dem7uovQOBg/+faZo8QkYSK9MW6eQkP+YnwN5zItNBxyGwKPbXXw" .
+ "Ey5/aqNWfhRY8IEG6HJgrnCwBMHUA14C2UV+Af7Cy4eNnC1Mmu7TmUYcFncXaFn0" .
+ "87ryFUdshlmPpIHxfjufAgMBAAGjggEaMIIBFjAJBgNVHRMEAjAAMAsGA1UdDwQE" .
+ "AwIDqDAdBgNVHQ4EFgQU2CY9Iex8275aOQxbcMsDgCHerhMwbQYDVR0jBGYwZIAU" .
+ "XafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQK" .
+ "ExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GC" .
+ "AQAwHgYDVR0RBBcwFYITbW9vbi5zdHJvbmdzd2FuLm9yZzATBgNVHSUEDDAKBggr" .
+ "BgEFBQcDATA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u" .
+ "b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQCpnj6Nc+PuPLPi" .
+ "4E3g5hyJkr5VZy7SSglcs1uyVP2mfwj6JR9SLd5+JOsL1aCTm0y9qLcqdbHBxG8i" .
+ "LNLtwVKU3s1hV4EIO3saHe4XUEjxN9bDtLWEoeq5ipmYX8RJ/fXKR8/8vurBARP2" .
+ "xu1+wqwEhymp4jBmF0LVovT1+o+GhH66zIJnx3zR9BtfMkaeL6804hrx2ygeopeo" .
+ "buGvMDQ8HcnMB9OU7Y8fK0oY1kULl6hf36K5ApPA6766sRRKRvBSKlmViKSQTq5a" .
+ "4c8gCWAZbtdT+N/fa8hKDlZt5q10EgjTqDfGTj50xKvAneq7XdfKmYYGnIWoNLY9" .
+ "ga8NOzX8\n" .
+ "-----END CERTIFICATE-----\n";
+
+my $ca_cert = "-----BEGIN CERTIFICATE-----\n" .
+ "MIIDuDCCAqCgAwIBAgIBADANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ" .
+ "MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS" .
+ "b290IENBMB4XDTA0MDkxMDEwMDExOFoXDTE5MDkwNzEwMDExOFowRTELMAkGA1UE" .
+ "BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u" .
+ "Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y" .
+ "X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f" .
+ "FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc" .
+ "4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/" .
+ "7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5" .
+ "gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr" .
+ "K+1LwdqRxo7HgMRiDw8CAwEAAaOBsjCBrzASBgNVHRMBAf8ECDAGAQH/AgEBMAsG" .
+ "A1UdDwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0j" .
+ "BGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkw" .
+ "FwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJv" .
+ "b3QgQ0GCAQAwDQYJKoZIhvcNAQELBQADggEBACOSmqEBtBLR9aV3UyCI8gmzR5in" .
+ "Lte9aUXXS+qis6F2h2Stf4sN+Nl6Gj7REC6SpfEH4wWdwiUL5J0CJhyoOjQuDl3n" .
+ "1Dw3dE4/zqMZdyDKEYTU75TmvusNJBdGsLkrf7EATAjoi/nrTOYPPhSUZvPp/D+Y" .
+ "vORJ9Ej51GXlK1nwEB5iA8+tDYniNQn6BD1MEgIejzK+fbiy7braZB1kqhoEr2Si" .
+ "7luBSnU912sw494E88a2EWbmMvg2TVHPNzCpVkpNk7kifCiwmw9VldkqYy9y/lCa" .
+ "Epyp7lTfKw7cbD04Vk8QJW782L6Csuxkl346b17wmOqn8AZips3tFsuAY3w=\n" .
+ "-----END CERTIFICATE-----\n" ;
+
+=pod
+
+The VICI interface requires a UNIX socket in order to communicate with the
+strongSwan charon daemon:
+
+ use IO::Socket::UNIX;
+
+ my $socket = IO::Socket::UNIX->new(
+ Type => SOCK_STREAM,
+ Peer => '/var/run/charon.vici',
+ ) or die "Vici socket: $!";
+
+=cut
+
+my $socket = IO::Socket::UNIX->new(
+ Type => SOCK_STREAM,
+ Peer => '/var/run/charon.vici',
+) or die "Vici socket: $!";
+
+=over
+
+=item new()
+
+creates a new Vici::Session object.
+
+ use Vici::Session;
+ use Vici::Message;
+
+ my $session = Vici::Session->new($socket);
+
+=cut
+
+my $session = Vici::Session->new($socket);
+
+=item version()
+
+returns daemon and system specific version information.
+
+ my $version = $session->version();
+
+=cut
+
+print "----- version -----\n";
+my $version = $session->version();
+print $version->raw(), "\n";
+
+=item load_cert()
+
+loads a certificate into the daemon.
+
+ my %vars = ( type => 'X509', flag => 'CA', data => $ca_cert );
+ my ($res, $errmsg) = $session->load_cert(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- load-cert -----\n";
+my %vars = ( type => 'X509', flag => 'CA', data => $ca_cert );
+my ($res, $errmsg) = $session->load_cert(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item load_key()
+
+loads a private key into the daemon.
+
+ my %vars = ( type => 'RSA', data => $moon_key );
+ my ($res, $errmsg) = $session->load_key(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- load-key -----\n";
+%vars = ( type => 'RSA', data => $moon_key );
+($res, $errmsg) = $session->load_key(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item load_shared()
+
+loads a shared IKE PSK, EAP or XAuth secret into the daemon.
+
+ my @owners = ( 'carol' );
+ my %vars = ( type => 'EAP', data => 'Ar3etTnp', owners => \@owners );
+ my ($res, $errmsg) = $session->load_shared(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- load-shared -----\n";
+my @owners = ( 'carol' );
+%vars = ( type => 'EAP', data => 'Ar3etTnp', owners => \@owners );
+($res, $errmsg) = $session->load_shared(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item load_authority()
+
+loads a single certification authority definition into the daemon. An existing
+authority with the same name gets replaced.
+
+ my @crl_uris = ( 'http://crl.strongswan.org/strongswan.crl' );
+ my @ocsp_uris = ( 'http://ocsp.strongswan.org:8880' );
+
+ my %auth = (
+ cacert => $ca_cert,
+ crl_uris => \@crl_uris,
+ ocsp_uris => \@ocsp_uris
+ );
+
+ my %vars = ( strongswan => \%auth );
+ my ($res, $errmsg) = $session->load_authority(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- load-authority -----\n";
+my @crl_uris = ( 'http://crl.strongswan.org/strongswan.crl' );
+my @ocsp_uris = ( 'http://ocsp.strongswan.org:8880' );
+my %auth = (
+ cacert => $ca_cert,
+ crl_uris => \@crl_uris,
+ ocsp_uris => \@ocsp_uris
+);
+%vars = ( strongswan => \%auth );
+($res, $errmsg) = $session->load_authority(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item load_conn()
+
+loads a single connection definition into the daemon. An existing connection
+with the same name gets updated or replaced.
+
+ my @l_ts = ( '10.1.0.0/16' );
+ my @r_ts = ( '10.2.0.0/16' );
+ my @esp = ( 'aes128gcm128-modp3072' );
+
+ my %child = (
+ local_ts => \@l_ts,
+ remote_ts => \@r_ts,
+ esp_proposals => \@esp,
+ );
+ my %children = ( 'net-net' => \%child );
+
+ my @l_addrs = ( '192.168.0.1' );
+ my @r_addrs = ( '192.168.0.2' );
+ my @l_certs = ( $moon_cert );
+ my %l = ( auth => 'pubkey', id => 'moon.strongswan.org',
+ certs => \@l_certs );
+ my %r = ( auth => 'pubkey', id => 'sun.strongswan.org');
+ my @ike = ( 'aes128-sha256-modp3072' );
+
+ my %gw = (
+ version => 2,
+ mobike => 'no',
+ proposals => \@ike,
+ local_addrs => \@l_addrs,
+ remote_addrs => \@r_addrs,
+ local => \%l,
+ remote => \%r,
+ children => \%children,
+ );
+
+ my %vars = ( 'gw-gw' => \%gw);
+ my ($res, $errmsg) = $session->load_conn(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- load-conn -----\n";
+my @l_ts = ( '10.1.0.0/16' );
+my @r_ts = ( '10.2.0.0/16' );
+my @esp = ( 'aes128gcm128-modp3072' );
+my %child = (
+ local_ts => \@l_ts,
+ remote_ts => \@r_ts,
+ esp_proposals => \@esp,
+);
+my %children = ( 'net-net' => \%child );
+my @l_addrs = ( '192.168.0.1' );
+my @r_addrs = ( '192.168.0.2' );
+my @l_certs = ( $moon_cert );
+my %l = ( auth => 'pubkey', id => 'moon.strongswan.org', certs => \@l_certs );
+my %r = ( auth => 'pubkey', id => 'sun.strongswan.org');
+my @ike = ( 'aes128-sha256-modp3072' );
+my %gw = (
+ version => 2,
+ mobike => 'no',
+ proposals => \@ike,
+ local_addrs => \@l_addrs,
+ remote_addrs => \@r_addrs,
+ local => \%l,
+ remote => \%r,
+ children => \%children,
+);
+%vars = ( 'gw-gw' => \%gw);
+($res, $errmsg) = $session->load_conn(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item get_algorithms()
+
+lists all currently loaded algorithms and their implementation.
+
+ my $algs = $session->get_algorithms();
+
+=cut
+
+print "----- get-algorithms -----\n";
+my $algs = $session->get_algorithms();
+print $algs->raw(), "\n";
+
+=item get_conns()
+
+returns a list of connection names loaded exclusively over VICI, not including
+connections found in other backends.
+
+ my $conns = $session->get_conns();
+
+=cut
+
+print "----- get-conns -----\n";
+my $conns = $session->get_conns();
+print $conns->raw(), "\n";
+
+=item list_conns()
+
+lists currently loaded connections by streaming list-conn events. This
+call includes all connections known by the daemon, not only those loaded
+over VICI.
+
+ my $conns = $session->list_conns();
+
+ foreach my $conn (@$conns)
+ {
+ print $conn->raw(), "\n";
+ }
+
+=cut
+
+print "----- list-conns -----\n";
+$conns = $session->list_conns();
+foreach my $conn (@$conns)
+{
+ print $conn->raw(), "\n";
+}
+
+=item initiate()
+
+initiates a CHILD_SA.
+
+ my %vars = ( child => 'net-net' );
+ my($res, $errmsg) = $session->initiate(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- initiate -----\n";
+%vars = ( child => 'net-net' );
+($res, $errmsg) = $session->initiate(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item list_sas()
+
+lists currently active IKE_SAs and associated CHILD_SAs by streaming list-sa
+events.
+
+ my $sas = $session->list_sas();
+
+ foreach my $sa (@$sas)
+ {
+ print $sa->raw(), "\n";
+ }
+
+=cut
+
+print "----- list-sas -----\n";
+my $sas = $session->list_sas();
+foreach my $sa (@$sas)
+{
+ print $sa->raw(), "\n";
+}
+
+=item get_authorities()
+
+returns a list of currently loaded certification authority names.
+
+ my $auths = $session->get_authorities();
+
+=cut
+
+print "----- get-authorities -----\n";
+my $auths = $session->get_authorities();
+print $auths->raw(), "\n";
+
+=item list-authorities()
+
+lists currently loaded certification authority information by streaming
+list-authority events.
+
+ my $auths = $session->list_authorities();
+
+ foreach my $auth (@$auths)
+ {
+ print $auth->raw(), "\n";
+ }
+
+=cut
+
+print "----- list-authorities -----\n";
+$auths = $session->list_authorities();
+foreach my $auth (@$auths)
+{
+ print $auth->raw(), "\n";
+}
+
+=item list_certs()
+
+lists currently loaded certificates by streaming list-cert events. This
+call includes all certificates known by the daemon, not only those loaded
+over VICI.
+
+ my %vars = ( subject => 'C=CH, O=Linux strongSwan, CN=moon.strongswan.org' );
+ my $certs = $session->list_certs(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- list-certs -----\n";
+%vars = ( subject => 'C=CH, O=Linux strongSwan, CN=moon.strongswan.org' );
+my $certs = $session->list_certs(Vici::Message->new(\%vars));
+foreach my $cert (@$certs)
+{
+ my $hash = $cert->hash();
+ print $hash->{'type'}, ": ", length($hash->{'data'}), ' bytes',
+ $hash->{'has_privkey'} ? ', has private key' : '', "\n";
+}
+
+=item stats()
+
+returns IKE daemon statistics and load information.
+
+ my $stats = $session->stats();
+
+=cut
+
+print "----- stats -----\n";
+my $stats = $session->stats();
+print $stats->raw(), "\n";
+
+=item terminate()
+
+terminates an IKE_SA or CHILD_SA.
+
+ my %vars = ( ike => 'gw-gw' );
+ my ($res, $errmsg) = $session->terminate(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- terminate -----\n";
+%vars = ( ike => 'gw-gw' );
+($res, $errmsg) = $session->terminate(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item install()
+
+installs a trap, drop or bypass policy defined by a CHILD_SA config.
+
+ my %vars = ( child => 'net-net' );
+ my ($res, $errmsg) = $session->install(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- install -----\n";
+%vars = ( child => 'net-net' );
+($res, $errmsg) = $session->install(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item list_policies()
+
+lists currently installed trap, drop and bypass policies by streaming
+list-policy events.
+
+ my %vars = ( trap => 'yes' );
+ my $pols = $session->list_policies(Vici::Message->new(\%vars));
+
+ foreach my $pol (@$pols)
+ {
+ print $pol->raw(), "\n";
+ }
+
+=cut
+
+print "----- list-policies -----\n";
+%vars = ( trap => 'yes' );
+my $pols = $session->list_policies(Vici::Message->new(\%vars));
+foreach my $pol (@$pols)
+{
+ print $pol->raw(), "\n";
+}
+
+=item uninstall()
+
+uninstalls a trap, drop or bypass policy defined by a CHILD_SA config.
+
+ my %vars = ( child => 'net-net' );
+ my ($res, $errmsg) = $session->uninstall(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- uninstall -----\n";
+%vars = ( child => 'net-net' );
+($res, $errmsg) = $session->uninstall(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item reload_settings()
+
+reloads strongswan.conf settings and all plugins supporting configuration
+reload.
+
+ my ($res, $errmsg) = $session->reload_settings();
+ print $res ? "ok\n" : "failed: $errmsg\n";
+
+=cut
+
+print "----- reload-settings -----\n";
+($res, $errmsg) = $session->reload_settings();
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item unload_conn()
+
+unloads a previously loaded connection definition by name.
+
+ my %vars = ( name => 'gw-gw' );
+ my ($res, $errmsg) = $session->unload_conn(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- unload-conn -----\n";
+%vars = ( name => 'gw-gw' );
+($res, $errmsg) = $session->unload_conn(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item unload_authority()
+
+unloads a previously loaded certification authority definition by name.
+
+ my %vars = ( name => 'strongswan' );
+ my ($res, $errmsg) = $session->unload_authority(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- unload-authority -----\n";
+%vars = ( name => 'strongswan' );
+($res, $errmsg) = $session->unload_authority(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item clear_creds()
+
+clears all loaded certificate, private key and shared key credentials. This
+affects only credentials loaded over vici, but additionally flushes the
+credential cache.
+
+ my ($res, $errmsg) = $session->clear_creds();
+
+=cut
+
+print "----- clear-creds -----\n";
+($res, $errmsg) = $session->clear_creds();
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item load_pool()
+
+loads an in-memory virtual IP and configuration attribute pool. Existing
+pools with the same name get updated, if possible.
+
+ my %pool = ( addrs => '10.3.0.0/23' );
+ my %vars = ( my_pool => \%pool );
+ my ($res, $errmsg) = $session->load_pool(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- load-pool -----\n";
+my %pool = ( addrs => '10.3.0.0/23' );
+%vars = ( my_pool => \%pool );
+($res, $errmsg) = $session->load_pool(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=item get_pools()
+
+lists the currently loaded pools.
+
+ my $pools = $session->get_pools();
+
+=cut
+
+print "----- get-pools -----\n";
+my $pools = $session->get_pools();
+print $pools->raw(), "\n";
+
+=item unload_pool()
+
+unloads a previously loaded virtual IP and configuration attribute pool.
+Unloading fails for pools with leases currently online.
+
+ my %vars = ( name => 'my_pool' );
+ my ($res, $errmsg) = $session->unload_pool(Vici::Message->new(\%vars));
+
+=cut
+
+print "----- unload-pool -----\n";
+%vars = ( name => 'my_pool' );
+($res, $errmsg) = $session->unload_pool(Vici::Message->new(\%vars));
+print $res ? "ok\n" : "failed: $errmsg\n";
+
+=back
+
+=cut
+
+# close vici socket
+close($socket);
+
+=head1 COPYRIGHT AND LICENCE
+
+Copyright (c) 2015 Andreas Steffen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Message.pm b/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Message.pm
new file mode 100644
index 000000000..b0a942c04
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Message.pm
@@ -0,0 +1,256 @@
+package Vici::Message;
+
+our $VERSION = '0.9';
+
+use strict;
+use Vici::Transport;
+
+use constant {
+ SECTION_START => 1, # Begin a new section having a name
+ SECTION_END => 2, # End a previously started section
+ KEY_VALUE => 3, # Define a value for a named key in the section
+ LIST_START => 4, # Begin a named list for list items
+ LIST_ITEM => 5, # Define an unnamed item value in the current list
+ LIST_END => 6, # End a previously started list
+};
+
+sub new {
+ my $class = shift;
+ my $hash = shift;
+ my $self = {
+ Hash => $hash
+ };
+ bless($self, $class);
+ return $self;
+}
+
+sub from_data {
+ my $class = shift;
+ my $data = shift;
+ my %hash = ();
+
+ parse($data, \%hash);
+
+ my $self = {
+ Hash => \%hash
+ };
+ bless($self, $class);
+ return $self;
+}
+
+sub hash {
+ my $self = shift;
+ return $self->{Hash};
+}
+
+sub encode {
+ my $self = shift;
+ return encode_hash($self->{'Hash'});
+}
+
+sub raw {
+ my $self = shift;
+ return '{' . raw_hash($self->{'Hash'}) . '}';
+}
+
+sub result {
+ my $self = shift;
+ my $result = $self->{'Hash'};
+ return ($result->{'success'} eq 'yes', $result->{'errmsg'});
+}
+
+# private functions
+
+sub parse {
+ my $data = shift;
+ my $hash = shift;
+
+ while (length($data) > 0)
+ {
+ (my $type, $data) = unpack('Ca*', $data);
+
+ if ($type == SECTION_END)
+ {
+ return $data;
+ }
+
+ (my $key, $data) = unpack('C/a*a*', $data);
+
+ if ( $type == KEY_VALUE )
+ {
+ (my $value, $data) = unpack('n/a*a*', $data);
+ $hash->{$key} = $value;
+ }
+ elsif ( $type == SECTION_START )
+ {
+ my %section = ();
+ $data = parse($data, \%section);
+ $hash->{$key} = \%section;
+ }
+ elsif ( $type == LIST_START )
+ {
+ my @list = ();
+ my $more = 1;
+
+ while (length($data) > 0 and $more)
+ {
+ (my $type, $data) = unpack('Ca*', $data);
+ if ( $type == LIST_ITEM )
+ {
+ (my $value, $data) = unpack('n/a*a*', $data);
+ push(@list, $value);
+ }
+ elsif ( $type == LIST_END )
+ {
+ $more = 0;
+ $hash->{$key} = \@list;
+ }
+ else
+ {
+ die "message parsing error: ", $type, "\n"
+ }
+ }
+ }
+ else
+ {
+ die "message parsing error: ", $type, "\n"
+ }
+ }
+ return $data;
+}
+
+
+sub encode_hash {
+ my $hash = shift;
+ my $enc = '';
+
+ while ( (my $key, my $value) = each %$hash )
+ {
+ if ( ref($value) eq 'HASH' )
+ {
+ $enc .= pack('CC/a*', SECTION_START, $key);
+ $enc .= encode_hash($value);
+ $enc .= pack('C', SECTION_END);
+ }
+ elsif ( ref($value) eq 'ARRAY' )
+ {
+ $enc .= pack('CC/a*', LIST_START, $key);
+
+ foreach my $item (@$value)
+ {
+ $enc .= pack('Cn/a*', LIST_ITEM, $item);
+ }
+ $enc .= pack('C', LIST_END);
+ }
+ else
+ {
+ $enc .= pack('CC/a*n/a*', KEY_VALUE, $key, $value);
+ }
+ }
+ return $enc;
+}
+
+sub raw_hash {
+ my $hash = shift;
+ my $raw = '';
+ my $first = 1;
+
+ while ( (my $key, my $value) = each %$hash )
+ {
+ if ($first)
+ {
+ $first = 0;
+ }
+ else
+ {
+ $raw .= ' ';
+ }
+ $raw .= $key;
+
+ if ( ref($value) eq 'HASH' )
+ {
+ $raw .= '{' . raw_hash($value) . '}';
+ }
+ elsif ( ref($value) eq 'ARRAY' )
+ {
+ my $first_item = 1;
+ $raw .= '[';
+
+ foreach my $item (@$value)
+ {
+ if ($first_item)
+ {
+ $first_item = 0;
+ }
+ else
+ {
+ $raw .= ' ';
+ }
+ $raw .= $item;
+ }
+ $raw .= ']';
+ }
+ else
+ {
+ $raw .= '=' . $value;
+ }
+ }
+ return $raw;
+}
+
+1;
+__END__
+=head1 NAME
+
+Vici::Message - Perl extension for building and parsing strongSwan VICI messages
+
+=head1 SYNOPSIS
+
+ use Vici::Message;
+
+=head1 DESCRIPTION
+
+The Vici::Message module is needed by the Vici::Session module to build and
+parse messages used in the communication with the open source strongSwan IPsec
+daemon (https://www.strongswan.com) via the documented Versatile IKE
+Configuration Interface (VICI). VICI allows the configuration, management and
+monitoring of multiple IPsec connections.
+
+=head2 EXPORT
+
+None by default.
+
+=head1 SEE ALSO
+
+strongSwan Wiki: https://wiki.strongswan.org/projects/strongswan/wiki/Vici
+
+strongSwan Mailing list: users@lists.strongswan.org
+
+=head1 AUTHOR
+
+Andreas Steffen, E<lt>andreas.steffen@strongswan.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Andreas Steffen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+=cut
+
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Packet.pm b/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Packet.pm
new file mode 100644
index 000000000..9e2b77fa5
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Packet.pm
@@ -0,0 +1,191 @@
+package Vici::Packet;
+
+our $VERSION = '0.9';
+
+use strict;
+use Vici::Message;
+use Vici::Transport;
+
+use constant {
+ CMD_REQUEST => 0, # Named request message
+ CMD_RESPONSE => 1, # Unnamed response message for a request
+ CMD_UNKNOWN => 2, # Unnamed response if requested command is unknown
+ EVENT_REGISTER => 3, # Named event registration request
+ EVENT_UNREGISTER => 4, # Named event de-registration request
+ EVENT_CONFIRM => 5, # Unnamed confirmation for event (de-)registration
+ EVENT_UNKNOWN => 6, # Unnamed response if event (de-)registration failed
+ EVENT => 7, # Named event message
+};
+
+sub new {
+ my $class = shift;
+ my $socket = shift;
+ my $self = {
+ Transport => Vici::Transport->new($socket),
+ };
+ bless($self, $class);
+ return $self;
+}
+
+sub request {
+ my ($self, $command, $vars) = @_;
+ my $out = defined $vars ? $vars->encode() : '';
+ my $request = pack('CC/a*a*', CMD_REQUEST, $command, $out);
+ $self->{'Transport'}->send($request);
+
+ my $response = $self->{'Transport'}->receive();
+ my ($type, $data) = unpack('Ca*', $response);
+
+ if ( $type == CMD_RESPONSE )
+ {
+ return Vici::Message->from_data($data);
+ }
+ elsif ( $type == CMD_UNKNOWN )
+ {
+ die "unknown command '", $command, "'\n"
+ }
+ else
+ {
+ die "invalid response type\n"
+ }
+}
+
+sub register {
+ my ($self, $event) = @_;
+ my $request = pack('CC/a*a*', EVENT_REGISTER, $event);
+ $self->{'Transport'}->send($request);
+
+ my $response = $self->{'Transport'}->receive();
+ my ($type, $data) = unpack('Ca*', $response);
+
+ if ( $type == EVENT_CONFIRM )
+ {
+ return
+ }
+ elsif ( $type == EVENT_UNKNOWN )
+ {
+ die "unknown event '", $event, "'\n"
+ }
+ else
+ {
+ die "invalid response type\n"
+ }
+}
+
+sub unregister {
+ my ($self, $event) = @_;
+ my $request = pack('CC/a*a*', EVENT_UNREGISTER, $event);
+ $self->{'Transport'}->send($request);
+
+ my $response = $self->{'Transport'}->receive();
+ my ($type, $data) = unpack('Ca*', $response);
+
+ if ( $type == EVENT_CONFIRM )
+ {
+ return
+ }
+ elsif ( $type == EVENT_UNKNOWN )
+ {
+ die "unknown event '", $event, "'\n"
+ }
+ else
+ {
+ die "invalid response type\n"
+ }
+}
+
+sub streamed_request {
+ my ($self, $command, $event, $vars) = @_;
+ my $out = defined $vars ? $vars->encode() : '';
+
+ $self->register($event);
+
+ my $request = pack('CC/a*a*', CMD_REQUEST, $command, $out);
+ $self->{'Transport'}->send($request);
+ my $more = 1;
+ my @list = ();
+
+ while ($more)
+ {
+ my $response = $self->{'Transport'}->receive();
+ my ($type, $data) = unpack('Ca*', $response);
+
+ if ( $type == EVENT )
+ {
+ (my $event_name, $data) = unpack('C/a*a*', $data);
+
+ if ($event_name eq $event)
+ {
+ my $msg = Vici::Message->from_data($data);
+ push(@list, $msg);
+ }
+ }
+ elsif ( $type == CMD_RESPONSE )
+ {
+ $self->unregister($event);
+ $more = 0;
+ }
+ else
+ {
+ $self->unregister($event);
+ die "invalid response type\n";
+ }
+ }
+ return \@list;
+}
+
+1;
+__END__
+=head1 NAME
+
+Vici::Packet - Perl extension for sending and receiving strongSwan VICI packets
+
+=head1 SYNOPSIS
+
+ use Vici::Packet;
+
+=head1 DESCRIPTION
+
+The Vici::Packet module is needed by the Vici::Session module to send and
+receive packets used in the communication with the open source strongSwan IPsec
+daemon (https://www.strongswan.com) via the documented Versatile IKE
+Configuration Interface (VICI). VICI allows the configuration, management and
+monitoring of multiple IPsec connections.
+
+=head2 EXPORT
+
+None by default.
+
+=head1 SEE ALSO
+
+strongSwan Wiki: https://wiki.strongswan.org/projects/strongswan/wiki/Vici
+
+strongSwan Mailing list: users@lists.strongswan.org
+
+=head1 AUTHOR
+
+Andreas Steffen, E<lt>andreas.steffen@strongswan.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Andreas Steffen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+=cut
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Session.pm b/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Session.pm
new file mode 100644
index 000000000..78197136a
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Session.pm
@@ -0,0 +1,204 @@
+package Vici::Session;
+
+our $VERSION = '0.9';
+
+use strict;
+use Vici::Packet;
+use Vici::Message;
+
+sub new {
+ my $class = shift;
+ my $socket = shift;
+ my $self = {
+ Packet => Vici::Packet->new($socket),
+ };
+ bless($self, $class);
+ return $self;
+}
+
+sub version {
+ return request('version', @_);
+}
+
+sub stats {
+ return request('stats', @_);
+}
+
+sub reload_settings {
+ return request_res('reload-settings', @_);
+}
+
+sub initiate {
+ return request_vars_res('initiate', @_);
+}
+
+sub terminate {
+ return request_vars_res('terminate', @_);
+}
+
+sub redirect {
+ return request_vars_res('redirect', @_);
+}
+
+sub install {
+ return request_vars_res('install', @_);
+}
+
+sub uninstall {
+ return request_vars_res('uninstall', @_);
+}
+
+sub list_sas {
+ return request_list('list-sas', 'list-sa', @_);
+}
+
+sub list_policies {
+ return request_list('list-policies', 'list-policy', @_);
+}
+
+sub list_conns {
+ return request_list('list-conns', 'list-conn', @_);
+}
+
+sub get_conns {
+ return request('get-conns', @_);
+}
+
+sub list_certs {
+ return request_list('list-certs', 'list-cert', @_);
+}
+
+sub list_authorities {
+ return request_list('list-authorities', 'list-authority', @_);
+}
+
+sub get_authorities {
+ return request('get-authorities', @_);
+}
+
+sub load_conn {
+ return request_vars_res('load-conn', @_);
+}
+
+sub unload_conn {
+ return request_vars_res('unload-conn', @_);
+}
+
+sub load_cert {
+ return request_vars_res('load-cert', @_);
+}
+
+sub load_key {
+ return request_vars_res('load-key', @_);
+}
+
+sub load_shared {
+ return request_vars_res('load-shared', @_);
+}
+
+sub clear_creds {
+ return request_res('clear-creds', @_);
+}
+
+sub load_authority {
+ return request_vars_res('load-authority', @_);
+}
+
+sub unload_authority {
+ return request_vars_res('unload-authority', @_);
+}
+
+sub load_pool {
+ return request_vars_res('load-pool', @_);
+}
+
+sub unload_pool {
+ return request_vars_res('unload-pool', @_);
+}
+
+sub get_pools {
+ return request('get-pools', @_);
+}
+
+sub get_algorithms {
+ return request('get-algorithms', @_);
+}
+
+# Private functions
+
+sub request {
+ my ($command, $self) = @_;
+ return $self->{'Packet'}->request($command);
+}
+
+sub request_res {
+ my ($command, $self) = @_;
+ my $msg = $self->{'Packet'}->request($command);
+ return $msg->result();
+}
+
+sub request_vars_res {
+ my ($command, $self, $vars) = @_;
+ my $msg = $self->{'Packet'}->request($command, $vars);
+ return $msg->result();
+}
+
+sub request_list {
+ my ($command, $event, $self, $vars) = @_;
+ return $self->{'Packet'}->streamed_request($command, $event, $vars);
+}
+
+1;
+__END__
+=head1 NAME
+
+Vici::Session - Perl binding for the strongSwan VICI configuration interface
+
+=head1 SYNOPSIS
+
+ use Vici::Session;
+
+=head1 DESCRIPTION
+
+The Vici::Session module allows a Perl script to communicate with the open
+source strongSwan IPsec daemon (https://www.strongswan.com) via the documented
+Versatile IKE Configuration Interface (VICI). VICI allows the configuration,
+management and monitoring of multiple IPsec connections.
+
+=head2 EXPORT
+
+None by default.
+
+=head1 SEE ALSO
+
+strongSwan Wiki: https://wiki.strongswan.org/projects/strongswan/wiki/Vici
+
+strongSwan Mailing list: users@lists.strongswan.org
+
+=head1 AUTHOR
+
+Andreas Steffen, E<lt>andreas.steffen@strongswan.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Andreas Steffen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+=cut
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Transport.pm b/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Transport.pm
new file mode 100644
index 000000000..6524bf76d
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Transport.pm
@@ -0,0 +1,88 @@
+package Vici::Transport;
+
+our $VERSION = '0.9';
+
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = {
+ Socket => shift,
+ };
+ bless($self, $class);
+ return $self;
+}
+
+sub send {
+ my ($self, $data) = @_;
+ my $packet = pack('N/a*', $data);
+ $self->{'Socket'}->send($packet);
+}
+
+sub receive {
+ my $self = shift;
+ my $packet_header;
+ my $data;
+
+ $self->{'Socket'}->recv($packet_header, 4);
+ my $packet_len = unpack('N', $packet_header);
+ $self->{'Socket'}->recv($data, $packet_len);
+ return $data;
+}
+
+1;
+__END__
+=head1 NAME
+
+Vici::Transport - Perl extension for communicating via a strongSwan VICI socket
+
+=head1 SYNOPSIS
+
+ use Vici::Transport;
+
+=head1 DESCRIPTION
+
+The Vici::Transport module is needed by the Vici::Packet module to send
+and receive packets over the UNIX socket used in the communication with the
+open source strongSwan IPsec daemon (https://www.strongswan.com) via the
+documented Versatile IKE Configuration Interface (VICI). VICI allows the
+onfiguration, management and monitoring of multiple IPsec connections.
+
+=head2 EXPORT
+
+None by default.
+
+=head1 SEE ALSO
+
+strongSwan Wiki: https://wiki.strongswan.org/projects/strongswan/wiki/Vici
+
+strongSwan Mailing list: users@lists.strongswan.org
+
+=head1 AUTHOR
+
+Andreas Steffen, E<lt>andreas.steffen@strongswan.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Andreas Steffen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+=cut
+
diff --git a/src/libcharon/plugins/vici/perl/Vici-Session/t/Vici-Session.t b/src/libcharon/plugins/vici/perl/Vici-Session/t/Vici-Session.t
new file mode 100644
index 000000000..4c321f3e1
--- /dev/null
+++ b/src/libcharon/plugins/vici/perl/Vici-Session/t/Vici-Session.t
@@ -0,0 +1,18 @@
+# Before 'make install' is performed this script should be runnable with
+# 'make test'. After 'make install' it should work as 'perl Vici-Session.t'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+BEGIN { use_ok('Vici::Session') };
+
+#########################
+
+# Insert your test code below, the Test::More module is use()ed here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+
diff --git a/src/libcharon/plugins/vici/python/Makefile.in b/src/libcharon/plugins/vici/python/Makefile.in
index eb4bab6ca..894a7e275 100644
--- a/src/libcharon/plugins/vici/python/Makefile.in
+++ b/src/libcharon/plugins/vici/python/Makefile.in
@@ -351,6 +351,8 @@ strongswan_conf = @strongswan_conf@
strongswan_options = @strongswan_options@
swanctldir = @swanctldir@
sysconfdir = @sysconfdir@
+systemd_CFLAGS = @systemd_CFLAGS@
+systemd_LIBS = @systemd_LIBS@
systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@
systemd_daemon_LIBS = @systemd_daemon_LIBS@
systemd_journal_CFLAGS = @systemd_journal_CFLAGS@
diff --git a/src/libcharon/plugins/vici/python/vici/session.py b/src/libcharon/plugins/vici/python/vici/session.py
index 283e3d13d..66de8590a 100644
--- a/src/libcharon/plugins/vici/python/vici/session.py
+++ b/src/libcharon/plugins/vici/python/vici/session.py
@@ -53,6 +53,14 @@ class Session(object):
"""
return self.handler.streamed_request("terminate", "control-log", sa)
+ def redirect(self, sa):
+ """Redirect an IKE_SA.
+
+ :param sa: the SA to redirect
+ :type sa: dict
+ """
+ self.handler.request("redirect", sa)
+
def install(self, policy):
"""Install a trap, drop or bypass policy defined by a CHILD_SA config.
diff --git a/src/libcharon/plugins/vici/ruby/Makefile.in b/src/libcharon/plugins/vici/ruby/Makefile.in
index bf81e5395..b87d83de4 100644
--- a/src/libcharon/plugins/vici/ruby/Makefile.in
+++ b/src/libcharon/plugins/vici/ruby/Makefile.in
@@ -329,6 +329,8 @@ strongswan_conf = @strongswan_conf@
strongswan_options = @strongswan_options@
swanctldir = @swanctldir@
sysconfdir = @sysconfdir@
+systemd_CFLAGS = @systemd_CFLAGS@
+systemd_LIBS = @systemd_LIBS@
systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@
systemd_daemon_LIBS = @systemd_daemon_LIBS@
systemd_journal_CFLAGS = @systemd_journal_CFLAGS@
diff --git a/src/libcharon/plugins/vici/ruby/lib/vici.rb b/src/libcharon/plugins/vici/ruby/lib/vici.rb
index f8169add0..018f50766 100644
--- a/src/libcharon/plugins/vici/ruby/lib/vici.rb
+++ b/src/libcharon/plugins/vici/ruby/lib/vici.rb
@@ -505,6 +505,12 @@ module Vici
end
##
+ # Redirect an IKE_SA.
+ def redirect(options)
+ check_success(@transp.request("redirect", Message.new(options)))
+ end
+
+ ##
# Install a shunt/route policy.
def install(policy)
check_success(@transp.request("install", Message.new(policy)))
diff --git a/src/libcharon/plugins/vici/vici_cert_info.c b/src/libcharon/plugins/vici/vici_cert_info.c
new file mode 100644
index 000000000..2f278de5e
--- /dev/null
+++ b/src/libcharon/plugins/vici/vici_cert_info.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 Andreas Steffen
+ * HSR 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 "vici_cert_info.h"
+
+/**
+ * Legacy vici certificate types and directories created by swanctl
+ */
+typedef struct {
+
+ /** Certificate type string used in legacy vici messages */
+ char *type_str;
+ /** Base certificate type */
+ certificate_type_t type;
+ /** X.509 flag */
+ x509_flag_t flag;
+} cert_type_t;
+
+static cert_type_t cert_types[] = {
+ { "x509", CERT_X509, X509_NONE },
+ { "x509ca", CERT_X509, X509_CA },
+ { "x509ocsp", CERT_X509, X509_OCSP_SIGNER },
+ { "x509aa", CERT_X509, X509_AA },
+ { "x509ac", CERT_X509_AC, X509_NONE },
+ { "x509crl", CERT_X509_CRL, X509_NONE },
+ { "pubkey", CERT_TRUSTED_PUBKEY, X509_NONE },
+};
+
+bool vici_cert_info_from_str(char *type_str, certificate_type_t *type,
+ x509_flag_t *flag)
+{
+ int i;
+
+ for (i = 0; i < countof(cert_types); i++)
+ {
+ if (strcaseeq(type_str, cert_types[i].type_str))
+ {
+ *type = cert_types[i].type;
+ *flag = cert_types[i].flag;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
diff --git a/src/libcharon/plugins/vici/vici_cert_info.h b/src/libcharon/plugins/vici/vici_cert_info.h
new file mode 100644
index 000000000..e2a8c4d9f
--- /dev/null
+++ b/src/libcharon/plugins/vici/vici_cert_info.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Andreas Steffen
+ * HSR 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.
+ */
+
+/**
+ * @defgroup vici_cert_info vici_cert_info
+ * @{ @ingroup vici
+ */
+
+#ifndef VICI_CERT_INFO_H_
+#define VICI_CERT_INFO_H_
+
+typedef struct vici_cert_info_t vici_cert_info_t;
+
+#include <credentials/certificates/certificate.h>
+#include <credentials/certificates/x509.h>
+
+bool vici_cert_info_from_str(char *type_str, certificate_type_t *type,
+ x509_flag_t *flag);
+
+#endif /** VICI_CERT_INFO_H_ @}*/
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index ea6d2958a..6ebbedc47 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -2,7 +2,8 @@
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
- * Copyright (C) 2015 Andreas Steffen
+ * Copyright (C) 2015-2016 Tobias Brunner
+ * Copyright (C) 2015-2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -45,9 +46,12 @@
#include <daemon.h>
#include <threading/rwlock.h>
+#include <threading/rwlock_condvar.h>
#include <collections/array.h>
#include <collections/linked_list.h>
+#include <pubkey_cert.h>
+
#include <stdio.h>
/**
@@ -98,6 +102,21 @@ struct private_vici_config_t {
rwlock_t *lock;
/**
+ * Condvar used to snyc running actions
+ */
+ rwlock_condvar_t *condvar;
+
+ /**
+ * True while we run or undo a start action
+ */
+ bool handling_actions;
+
+ /**
+ * Credential backend managed by VICI used for our certificates
+ */
+ vici_cred_t *cred;
+
+ /**
* Auxiliary certification authority information
*/
vici_authority_t *authority;
@@ -218,6 +237,24 @@ typedef struct {
} request_data_t;
/**
+ * Auth config data
+ */
+typedef struct {
+ request_data_t *request;
+ auth_cfg_t *cfg;
+ u_int32_t round;
+} auth_data_t;
+
+/**
+ * Clean up auth config data
+ */
+static void free_auth_data(auth_data_t *data)
+{
+ DESTROY_IF(data->cfg);
+ free(data);
+}
+
+/**
* Data associated to a peer config
*/
typedef struct {
@@ -311,7 +348,7 @@ static void log_auth(auth_cfg_t *auth)
static void log_peer_data(peer_data_t *data)
{
enumerator_t *enumerator;
- auth_cfg_t *auth;
+ auth_data_t *auth;
host_t *host;
DBG2(DBG_CFG, " version = %u", data->version);
@@ -350,7 +387,7 @@ static void log_peer_data(peer_data_t *data)
while (enumerator->enumerate(enumerator, &auth))
{
DBG2(DBG_CFG, " local:");
- log_auth(auth);
+ log_auth(auth->cfg);
}
enumerator->destroy(enumerator);
@@ -358,7 +395,7 @@ static void log_peer_data(peer_data_t *data)
while (enumerator->enumerate(enumerator, &auth))
{
DBG2(DBG_CFG, " remote:");
- log_auth(auth);
+ log_auth(auth->cfg);
}
enumerator->destroy(enumerator);
}
@@ -368,10 +405,8 @@ static void log_peer_data(peer_data_t *data)
*/
static void free_peer_data(peer_data_t *data)
{
- data->local->destroy_offset(data->local,
- offsetof(auth_cfg_t, destroy));
- data->remote->destroy_offset(data->remote,
- offsetof(auth_cfg_t, destroy));
+ data->local->destroy_function(data->local, (void*)free_auth_data);
+ data->remote->destroy_function(data->remote, (void*)free_auth_data);
data->children->destroy_offset(data->children,
offsetof(child_cfg_t, destroy));
data->proposals->destroy_offset(data->proposals,
@@ -461,14 +496,6 @@ static void free_child_data(child_data_t *data)
}
/**
- * Auth config data
- */
-typedef struct {
- request_data_t *request;
- auth_cfg_t *cfg;
-} auth_data_t;
-
-/**
* Common proposal parsing
*/
static bool parse_proposal(linked_list_t *list, protocol_id_t proto, chunk_t v)
@@ -537,7 +564,7 @@ CALLBACK(parse_ts, bool,
linked_list_t *out, chunk_t v)
{
char buf[128], *protoport, *sep, *port = "", *end;
- traffic_selector_t *ts;
+ traffic_selector_t *ts = NULL;
struct protoent *protoent;
struct servent *svc;
long int p;
@@ -630,6 +657,22 @@ CALLBACK(parse_ts, bool,
{
ts = traffic_selector_create_dynamic(proto, from, to);
}
+ else if (strchr(buf, '-'))
+ {
+ host_t *lower, *upper;
+ ts_type_t type;
+
+ if (host_create_from_range(buf, &lower, &upper))
+ {
+ type = (lower->get_family(lower) == AF_INET) ?
+ TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
+ ts = traffic_selector_create_from_bytes(proto, type,
+ lower->get_address(lower), from,
+ upper->get_address(upper), to);
+ lower->destroy(lower);
+ upper->destroy(upper);
+ }
+ }
else
{
ts = traffic_selector_create_from_cidr(buf, proto, from, to);
@@ -948,9 +991,14 @@ CALLBACK(parse_auth, bool,
{
return FALSE;
}
- if (strcaseeq(buf, "pubkey"))
+ if (strpfx(buf, "ike:") ||
+ strpfx(buf, "pubkey") ||
+ strpfx(buf, "rsa") ||
+ strpfx(buf, "ecdsa") ||
+ strpfx(buf, "bliss"))
{
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
+ cfg->add_pubkey_constraints(cfg, buf, TRUE);
return TRUE;
}
if (strcaseeq(buf, "psk"))
@@ -970,8 +1018,16 @@ CALLBACK(parse_auth, bool,
}
if (strcasepfx(buf, "eap"))
{
+ char *pos;
+
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
+ pos = strchr(buf, ':');
+ if (pos)
+ {
+ *pos = 0;
+ cfg->add_pubkey_constraints(cfg, pos + 1, FALSE);
+ }
type = eap_vendor_type_from_string(buf);
if (type)
{
@@ -1053,6 +1109,7 @@ CALLBACK(parse_group, bool,
static bool parse_cert(auth_data_t *auth, auth_rule_t rule, chunk_t v)
{
vici_authority_t *authority;
+ vici_cred_t *cred;
certificate_t *cert;
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
@@ -1064,6 +1121,8 @@ static bool parse_cert(auth_data_t *auth, auth_rule_t rule, chunk_t v)
authority = auth->request->this->authority;
authority->check_for_hash_and_url(authority, cert);
}
+ cred = auth->request->this->cred;
+ cert = cred->add_cert(cred, cert);
auth->cfg->add(auth->cfg, rule, cert);
return TRUE;
}
@@ -1089,6 +1148,27 @@ CALLBACK(parse_cacerts, bool,
}
/**
+ * Parse raw public keys
+ */
+CALLBACK(parse_pubkeys, bool,
+ auth_data_t *auth, chunk_t v)
+{
+ vici_cred_t *cred;
+ certificate_t *cert;
+
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
+ BUILD_BLOB_PEM, v, BUILD_END);
+ if (cert)
+ {
+ cred = auth->request->this->cred;
+ cert = cred->add_cert(cred, cert);
+ auth->cfg->add(auth->cfg, AUTH_RULE_SUBJECT_CERT, cert);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
* Parse revocation status
*/
CALLBACK(parse_revocation, bool,
@@ -1283,6 +1363,7 @@ CALLBACK(auth_li, bool,
{ "groups", parse_group, auth->cfg },
{ "certs", parse_certs, auth },
{ "cacerts", parse_cacerts, auth },
+ { "pubkeys", parse_pubkeys, auth },
};
return parse_rules(rules, countof(rules), name, value,
@@ -1299,6 +1380,7 @@ CALLBACK(auth_kv, bool,
{ "eap_id", parse_eap_id, auth->cfg },
{ "xauth_id", parse_xauth_id, auth->cfg },
{ "revocation", parse_revocation, auth->cfg },
+ { "round", parse_uint32, &auth->round },
};
return parse_rules(rules, countof(rules), name, value,
@@ -1502,40 +1584,62 @@ CALLBACK(peer_sn, bool,
if (strcasepfx(name, "local") ||
strcasepfx(name, "remote"))
{
- auth_data_t auth = {
+ enumerator_t *enumerator;
+ linked_list_t *auths;
+ auth_data_t *auth, *current;
+ auth_rule_t rule;
+ certificate_t *cert;
+ pubkey_cert_t *pubkey_cert;
+ identification_t *id;
+ bool default_id = FALSE;
+
+ INIT(auth,
.request = peer->request,
.cfg = auth_cfg_create(),
- };
+ );
- if (!message->parse(message, ctx, NULL, auth_kv, auth_li, &auth))
+ if (!message->parse(message, ctx, NULL, auth_kv, auth_li, auth))
{
- auth.cfg->destroy(auth.cfg);
+ free_auth_data(auth);
return FALSE;
}
+ id = auth->cfg->get(auth->cfg, AUTH_RULE_IDENTITY);
- if (!auth.cfg->get(auth.cfg, AUTH_RULE_IDENTITY))
+ enumerator = auth->cfg->create_enumerator(auth->cfg);
+ while (enumerator->enumerate(enumerator, &rule, &cert))
{
- identification_t *id;
- certificate_t *cert;
-
- cert = auth.cfg->get(auth.cfg, AUTH_RULE_SUBJECT_CERT);
- if (cert)
+ if (rule == AUTH_RULE_SUBJECT_CERT && !default_id)
{
- id = cert->get_subject(cert);
- DBG1(DBG_CFG, " id not specified, defaulting to cert id '%Y'",
- id);
- auth.cfg->add(auth.cfg, AUTH_RULE_IDENTITY, id->clone(id));
+ if (id == NULL)
+ {
+ id = cert->get_subject(cert);
+ DBG1(DBG_CFG, " id not specified, defaulting to"
+ " cert subject '%Y'", id);
+ auth->cfg->add(auth->cfg, AUTH_RULE_IDENTITY, id->clone(id));
+ default_id = TRUE;
+ }
+ else if (cert->get_type(cert) == CERT_TRUSTED_PUBKEY &&
+ id->get_type != ID_ANY)
+ {
+ /* set the subject of all raw public keys to the id */
+ pubkey_cert = (pubkey_cert_t*)cert;
+ pubkey_cert->set_subject(pubkey_cert, id);
+ }
}
}
+ enumerator->destroy(enumerator);
- if (strcasepfx(name, "local"))
+ auths = strcasepfx(name, "local") ? peer->local : peer->remote;
+ enumerator = auths->create_enumerator(auths);
+ while (enumerator->enumerate(enumerator, &current))
{
- peer->local->insert_last(peer->local, auth.cfg);
- }
- else
- {
- peer->remote->insert_last(peer->remote, auth.cfg);
+ if (auth->round < current->round)
+ {
+ break;
+ }
}
+ auths->insert_before(auths, enumerator, auth);
+ enumerator->destroy(enumerator);
return TRUE;
}
peer->request->reply = create_reply("invalid section: %s", name);
@@ -1578,7 +1682,7 @@ static u_int32_t find_reqid(child_cfg_t *cfg)
}
/**
- * Perform start actions associated to a child config
+ * Perform start actions associated with a child config
*/
static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
child_cfg_t *child_cfg)
@@ -1611,19 +1715,20 @@ static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
}
/**
- * Undo start actions associated to a child config
+ * Undo start actions associated with a child config
*/
-static void clear_start_action(private_vici_config_t *this,
+static void clear_start_action(private_vici_config_t *this, char *peer_name,
child_cfg_t *child_cfg)
{
enumerator_t *enumerator, *children;
child_sa_t *child_sa;
ike_sa_t *ike_sa;
- u_int32_t id = 0, *del;
- array_t *ids = NULL;
+ u_int32_t id = 0, others;
+ array_t *ids = NULL, *ikeids = NULL;
char *name;
name = child_cfg->get_name(child_cfg);
+
switch (child_cfg->get_start_action(child_cfg))
{
case ACTION_RESTART:
@@ -1631,29 +1736,72 @@ static void clear_start_action(private_vici_config_t *this,
charon->controller, TRUE);
while (enumerator->enumerate(enumerator, &ike_sa))
{
+ if (!streq(ike_sa->get_name(ike_sa), peer_name))
+ {
+ continue;
+ }
+ others = id = 0;
children = ike_sa->create_child_sa_enumerator(ike_sa);
while (children->enumerate(children, &child_sa))
{
- if (streq(name, child_sa->get_name(child_sa)))
+ if (child_sa->get_state(child_sa) != CHILD_DELETING)
{
- id = child_sa->get_unique_id(child_sa);
- array_insert_create(&ids, ARRAY_TAIL, &id);
+ if (streq(name, child_sa->get_name(child_sa)))
+ {
+ id = child_sa->get_unique_id(child_sa);
+ }
+ else
+ {
+ others++;
+ }
}
}
children->destroy(children);
+
+ if (id && !others)
+ {
+ /* found matching children only, delete full IKE_SA */
+ id = ike_sa->get_unique_id(ike_sa);
+ array_insert_create_value(&ikeids, sizeof(id),
+ ARRAY_TAIL, &id);
+ }
+ else
+ {
+ children = ike_sa->create_child_sa_enumerator(ike_sa);
+ while (children->enumerate(children, &child_sa))
+ {
+ if (streq(name, child_sa->get_name(child_sa)))
+ {
+ id = child_sa->get_unique_id(child_sa);
+ array_insert_create_value(&ids, sizeof(id),
+ ARRAY_TAIL, &id);
+ }
+ }
+ children->destroy(children);
+ }
}
enumerator->destroy(enumerator);
if (array_count(ids))
{
- while (array_remove(ids, ARRAY_HEAD, &del))
+ while (array_remove(ids, ARRAY_HEAD, &id))
{
- DBG1(DBG_CFG, "closing '%s' #%u", name, *del);
+ DBG1(DBG_CFG, "closing '%s' #%u", name, id);
charon->controller->terminate_child(charon->controller,
- *del, NULL, NULL, 0);
+ id, NULL, NULL, 0);
}
array_destroy(ids);
}
+ if (array_count(ikeids))
+ {
+ while (array_remove(ikeids, ARRAY_HEAD, &id))
+ {
+ DBG1(DBG_CFG, "closing IKE_SA #%u", id);
+ charon->controller->terminate_ike(charon->controller,
+ id, NULL, NULL, 0);
+ }
+ array_destroy(ikeids);
+ }
break;
case ACTION_ROUTE:
DBG1(DBG_CFG, "uninstalling '%s'", name);
@@ -1687,36 +1835,56 @@ static void clear_start_action(private_vici_config_t *this,
}
/**
- * Run start actions associated to all child configs of a peer config
+ * Run or undo a start actions associated with a child config
*/
-static void run_start_actions(private_vici_config_t *this, peer_cfg_t *peer_cfg)
+static void handle_start_action(private_vici_config_t *this,
+ peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
+ bool undo)
{
- enumerator_t *enumerator;
- child_cfg_t *child_cfg;
+ this->handling_actions = TRUE;
+ this->lock->unlock(this->lock);
- enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
- while (enumerator->enumerate(enumerator, &child_cfg))
+ if (undo)
+ {
+ clear_start_action(this, peer_cfg->get_name(peer_cfg), child_cfg);
+ }
+ else
{
run_start_action(this, peer_cfg, child_cfg);
}
- enumerator->destroy(enumerator);
+
+ this->lock->write_lock(this->lock);
+ this->handling_actions = FALSE;
}
/**
- * Undo start actions associated to all child configs of a peer config
+ * Run or undo start actions associated with all child configs of a peer config
*/
-static void clear_start_actions(private_vici_config_t *this,
- peer_cfg_t *peer_cfg)
+static void handle_start_actions(private_vici_config_t *this,
+ peer_cfg_t *peer_cfg, bool undo)
{
enumerator_t *enumerator;
child_cfg_t *child_cfg;
+ this->handling_actions = TRUE;
+ this->lock->unlock(this->lock);
+
enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
while (enumerator->enumerate(enumerator, &child_cfg))
{
- clear_start_action(this, child_cfg);
+ if (undo)
+ {
+ clear_start_action(this, peer_cfg->get_name(peer_cfg), child_cfg);
+ }
+ else
+ {
+ run_start_action(this, peer_cfg, child_cfg);
+ }
}
enumerator->destroy(enumerator);
+
+ this->lock->write_lock(this->lock);
+ this->handling_actions = FALSE;
}
/**
@@ -1727,22 +1895,12 @@ static void replace_children(private_vici_config_t *this,
{
enumerator_t *enumerator;
child_cfg_t *child;
+ bool added;
- enumerator = to->create_child_cfg_enumerator(to);
- while (enumerator->enumerate(enumerator, &child))
+ enumerator = to->replace_child_cfgs(to, from);
+ while (enumerator->enumerate(enumerator, &child, &added))
{
- to->remove_child_cfg(to, enumerator);
- clear_start_action(this, child);
- child->destroy(child);
- }
- enumerator->destroy(enumerator);
-
- enumerator = from->create_child_cfg_enumerator(from);
- while (enumerator->enumerate(enumerator, &child))
- {
- from->remove_child_cfg(from, enumerator);
- to->add_child_cfg(to, child);
- run_start_action(this, to, child);
+ handle_start_action(this, to, child, !added);
}
enumerator->destroy(enumerator);
}
@@ -1758,6 +1916,10 @@ static void merge_config(private_vici_config_t *this, peer_cfg_t *peer_cfg)
bool merged = FALSE;
this->lock->write_lock(this->lock);
+ while (this->handling_actions)
+ {
+ this->condvar->wait(this->condvar, this->lock);
+ }
enumerator = this->conns->create_enumerator(this->conns);
while (enumerator->enumerate(enumerator, &current))
@@ -1778,10 +1940,10 @@ static void merge_config(private_vici_config_t *this, peer_cfg_t *peer_cfg)
DBG1(DBG_CFG, "replaced vici connection: %s",
peer_cfg->get_name(peer_cfg));
this->conns->remove_at(this->conns, enumerator);
- clear_start_actions(this, current);
- current->destroy(current);
this->conns->insert_last(this->conns, peer_cfg);
- run_start_actions(this, peer_cfg);
+ handle_start_actions(this, current, TRUE);
+ handle_start_actions(this, peer_cfg, FALSE);
+ current->destroy(current);
}
merged = TRUE;
break;
@@ -1793,9 +1955,9 @@ static void merge_config(private_vici_config_t *this, peer_cfg_t *peer_cfg)
{
DBG1(DBG_CFG, "added vici connection: %s", peer_cfg->get_name(peer_cfg));
this->conns->insert_last(this->conns, peer_cfg);
- run_start_actions(this, peer_cfg);
+ handle_start_actions(this, peer_cfg, FALSE);
}
-
+ this->condvar->signal(this->condvar);
this->lock->unlock(this->lock);
}
@@ -1828,7 +1990,7 @@ CALLBACK(config_sn, bool,
peer_cfg_t *peer_cfg;
ike_cfg_t *ike_cfg;
child_cfg_t *child_cfg;
- auth_cfg_t *auth_cfg;
+ auth_data_t *auth;
proposal_t *proposal;
host_t *host;
char *str;
@@ -1843,14 +2005,17 @@ CALLBACK(config_sn, bool,
if (peer.local->get_count(peer.local) == 0)
{
- free_peer_data(&peer);
- peer.request->reply = create_reply("missing local auth config");
- return FALSE;
+ INIT(auth,
+ .cfg = auth_cfg_create(),
+ );
+ peer.local->insert_last(peer.local, auth);
}
if (peer.remote->get_count(peer.remote) == 0)
{
- auth_cfg = auth_cfg_create();
- peer.remote->insert_last(peer.remote, auth_cfg);
+ INIT(auth,
+ .cfg = auth_cfg_create(),
+ );
+ peer.remote->insert_last(peer.remote, auth);
}
if (peer.proposals->get_count(peer.proposals) == 0)
{
@@ -1926,14 +2091,18 @@ CALLBACK(config_sn, bool,
FALSE, NULL, NULL);
while (peer.local->remove_first(peer.local,
- (void**)&auth_cfg) == SUCCESS)
+ (void**)&auth) == SUCCESS)
{
- peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
+ peer_cfg->add_auth_cfg(peer_cfg, auth->cfg, TRUE);
+ auth->cfg = NULL;
+ free_auth_data(auth);
}
while (peer.remote->remove_first(peer.remote,
- (void**)&auth_cfg) == SUCCESS)
+ (void**)&auth) == SUCCESS)
{
- peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
+ peer_cfg->add_auth_cfg(peer_cfg, auth->cfg, FALSE);
+ auth->cfg = NULL;
+ free_auth_data(auth);
}
while (peer.children->remove_first(peer.children,
(void**)&child_cfg) == SUCCESS)
@@ -1999,18 +2168,24 @@ CALLBACK(unload_conn, vici_message_t*,
}
this->lock->write_lock(this->lock);
+ while (this->handling_actions)
+ {
+ this->condvar->wait(this->condvar, this->lock);
+ }
enumerator = this->conns->create_enumerator(this->conns);
while (enumerator->enumerate(enumerator, &cfg))
{
if (streq(cfg->get_name(cfg), conn_name))
{
this->conns->remove_at(this->conns, enumerator);
+ handle_start_actions(this, cfg, TRUE);
cfg->destroy(cfg);
found = TRUE;
break;
}
}
enumerator->destroy(enumerator);
+ this->condvar->signal(this->condvar);
this->lock->unlock(this->lock);
if (!found)
@@ -2066,6 +2241,7 @@ METHOD(vici_config_t, destroy, void,
{
manage_commands(this, FALSE);
this->conns->destroy_offset(this->conns, offsetof(peer_cfg_t, destroy));
+ this->condvar->destroy(this->condvar);
this->lock->destroy(this->lock);
free(this);
}
@@ -2074,7 +2250,8 @@ METHOD(vici_config_t, destroy, void,
* See header
*/
vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher,
- vici_authority_t *authority)
+ vici_authority_t *authority,
+ vici_cred_t *cred)
{
private_vici_config_t *this;
@@ -2090,7 +2267,9 @@ vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher,
.dispatcher = dispatcher,
.conns = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .condvar = rwlock_condvar_create(),
.authority = authority,
+ .cred = cred,
);
manage_commands(this, TRUE);
diff --git a/src/libcharon/plugins/vici/vici_config.h b/src/libcharon/plugins/vici/vici_config.h
index c3245bf5c..0c237e7de 100644
--- a/src/libcharon/plugins/vici/vici_config.h
+++ b/src/libcharon/plugins/vici/vici_config.h
@@ -26,6 +26,7 @@
#include "vici_dispatcher.h"
#include "vici_authority.h"
+#include "vici_cred.h"
#include <config/backend.h>
@@ -51,9 +52,11 @@ struct vici_config_t {
*
* @param dispatcher dispatcher to receive requests from
* @param authority Auxiliary certification authority information
+ * @param cred in-memory credential backend managed by VICI
* @return config backend
*/
vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher,
- vici_authority_t *authority);
+ vici_authority_t *authority,
+ vici_cred_t *cred);
#endif /** VICI_CONFIG_H_ @}*/
diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c
index 752007c24..c526d2fda 100644
--- a/src/libcharon/plugins/vici/vici_control.c
+++ b/src/libcharon/plugins/vici/vici_control.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
@@ -20,6 +23,7 @@
#include <daemon.h>
#include <collections/array.h>
+#include <processing/jobs/redirect_job.h>
typedef struct private_vici_control_t private_vici_control_t;
@@ -134,7 +138,7 @@ static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
/**
* Find a peer/child config from a child config name
*/
-static child_cfg_t* find_child_cfg(char *name, peer_cfg_t **out)
+static child_cfg_t* find_child_cfg(char *name, char *pname, peer_cfg_t **out)
{
enumerator_t *enumerator;
peer_cfg_t *peer_cfg;
@@ -144,6 +148,10 @@ static child_cfg_t* find_child_cfg(char *name, peer_cfg_t **out)
charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
while (enumerator->enumerate(enumerator, &peer_cfg))
{
+ if (pname && !streq(pname, peer_cfg->get_name(peer_cfg)))
+ {
+ continue;
+ }
child_cfg = get_child_from_peer(peer_cfg, name);
if (child_cfg)
{
@@ -161,15 +169,17 @@ CALLBACK(initiate, vici_message_t*,
{
child_cfg_t *child_cfg = NULL;
peer_cfg_t *peer_cfg;
- char *child;
- u_int timeout;
+ char *child, *ike;
+ int timeout;
bool limits;
+ controller_cb_t log_cb = NULL;
log_info_t log = {
.dispatcher = this->dispatcher,
.id = id,
};
child = request->get_str(request, NULL, "child");
+ ike = request->get_str(request, NULL, "ike");
timeout = request->get_int(request, 0, "timeout");
limits = request->get_bool(request, FALSE, "init-limits");
log.level = request->get_int(request, 1, "loglevel");
@@ -178,16 +188,20 @@ CALLBACK(initiate, vici_message_t*,
{
return send_reply(this, "missing configuration name");
}
+ if (timeout >= 0)
+ {
+ log_cb = (controller_cb_t)log_vici;
+ }
DBG1(DBG_CFG, "vici initiate '%s'", child);
- child_cfg = find_child_cfg(child, &peer_cfg);
+ child_cfg = find_child_cfg(child, ike, &peer_cfg);
if (!child_cfg)
{
return send_reply(this, "CHILD_SA config '%s' not found", child);
}
switch (charon->controller->initiate(charon->controller, peer_cfg,
- child_cfg, (controller_cb_t)log_vici, &log, timeout, limits))
+ child_cfg, log_cb, &log, timeout, limits))
{
case SUCCESS:
return send_reply(this, NULL);
@@ -208,11 +222,13 @@ CALLBACK(terminate, vici_message_t*,
{
enumerator_t *enumerator, *isas, *csas;
char *child, *ike, *errmsg = NULL;
- u_int timeout, child_id, ike_id, current, *del, done = 0;
+ u_int child_id, ike_id, current, *del, done = 0;
+ int timeout;
ike_sa_t *ike_sa;
child_sa_t *child_sa;
array_t *ids;
vici_builder_t *builder;
+ controller_cb_t log_cb = NULL;
log_info_t log = {
.dispatcher = this->dispatcher,
.id = id,
@@ -247,6 +263,11 @@ CALLBACK(terminate, vici_message_t*,
DBG1(DBG_CFG, "vici terminate CHILD_SA '%s'", child);
}
+ if (timeout >= 0)
+ {
+ log_cb = (controller_cb_t)log_vici;
+ }
+
ids = array_create(sizeof(u_int), 0);
isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE);
@@ -296,7 +317,7 @@ CALLBACK(terminate, vici_message_t*,
if (child || child_id)
{
if (charon->controller->terminate_child(charon->controller, *del,
- (controller_cb_t)log_vici, &log, timeout) == SUCCESS)
+ log_cb, &log, timeout) == SUCCESS)
{
done++;
}
@@ -304,7 +325,7 @@ CALLBACK(terminate, vici_message_t*,
else
{
if (charon->controller->terminate_ike(charon->controller, *del,
- (controller_cb_t)log_vici, &log, timeout) == SUCCESS)
+ log_cb, &log, timeout) == SUCCESS)
{
done++;
}
@@ -340,6 +361,150 @@ CALLBACK(terminate, vici_message_t*,
}
/**
+ * Parse a peer-ip specified, which can be a subnet in CIDR notation, a range
+ * or a single IP address.
+ */
+static traffic_selector_t *parse_peer_ip(char *ip)
+{
+ traffic_selector_t *ts;
+ host_t *from, *to;
+ ts_type_t type;
+
+ if (host_create_from_range(ip, &from, &to))
+ {
+ if (to->get_family(to) == AF_INET)
+ {
+ type = TS_IPV4_ADDR_RANGE;
+ }
+ else
+ {
+ type = TS_IPV6_ADDR_RANGE;
+ }
+ ts = traffic_selector_create_from_bytes(0, type,
+ from->get_address(from), 0,
+ to->get_address(to), 0xFFFF);
+ from->destroy(from);
+ to->destroy(to);
+ return ts;
+ }
+ return traffic_selector_create_from_cidr(ip, 0, 0, 0xFFFF);
+}
+
+CALLBACK(redirect, vici_message_t*,
+ private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
+{
+ enumerator_t *sas;
+ char *ike, *peer_ip, *peer_id, *gw, *errmsg = NULL;
+ u_int ike_id, current, found = 0;
+ identification_t *gateway, *identity = NULL, *other_id;
+ traffic_selector_t *ts = NULL;
+ ike_sa_t *ike_sa;
+ vici_builder_t *builder;
+
+ ike = request->get_str(request, NULL, "ike");
+ ike_id = request->get_int(request, 0, "ike-id");
+ peer_ip = request->get_str(request, NULL, "peer-ip");
+ peer_id = request->get_str(request, NULL, "peer-id");
+ gw = request->get_str(request, NULL, "gateway");
+
+ if (!gw || !(gateway = identification_create_from_string(gw)))
+ {
+ return send_reply(this, "missing target gateway");
+ }
+ switch (gateway->get_type(gateway))
+ {
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ case ID_FQDN:
+ break;
+ default:
+ return send_reply(this, "unsupported gateway identity");
+ }
+ if (peer_ip)
+ {
+ ts = parse_peer_ip(peer_ip);
+ if (!ts)
+ {
+ return send_reply(this, "invalid peer IP selector");
+ }
+ DBG1(DBG_CFG, "vici redirect IKE_SAs with src %R to %Y", ts,
+ gateway);
+ }
+ if (peer_id)
+ {
+ identity = identification_create_from_string(peer_id);
+ if (!identity)
+ {
+ DESTROY_IF(ts);
+ return send_reply(this, "invalid peer identity selector");
+ }
+ DBG1(DBG_CFG, "vici redirect IKE_SAs with ID '%Y' to %Y", identity,
+ gateway);
+ }
+ if (ike_id)
+ {
+ DBG1(DBG_CFG, "vici redirect IKE_SA #%d to '%Y'", ike_id, gateway);
+ }
+ if (ike)
+ {
+ DBG1(DBG_CFG, "vici redirect IKE_SA '%s' to '%Y'", ike, gateway);
+ }
+ if (!peer_ip && !peer_id && !ike && !ike_id)
+ {
+ return send_reply(this, "missing redirect selector");
+ }
+
+ sas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE);
+ while (sas->enumerate(sas, &ike_sa))
+ {
+ if (ike_sa->get_version(ike_sa) != IKEV2)
+ {
+ continue;
+ }
+ current = ike_sa->get_unique_id(ike_sa);
+ if (ike_id && ike_id != current)
+ {
+ continue;
+ }
+ if (ike && !streq(ike, ike_sa->get_name(ike_sa)))
+ {
+ continue;
+ }
+ if (ts && !ts->includes(ts, ike_sa->get_other_host(ike_sa)))
+ {
+ continue;
+ }
+ if (identity)
+ {
+ other_id = ike_sa->get_other_eap_id(ike_sa);
+ if (!other_id->matches(other_id, identity))
+ {
+ continue;
+ }
+ }
+ lib->processor->queue_job(lib->processor,
+ (job_t*)redirect_job_create(ike_sa->get_id(ike_sa), gateway));
+ found++;
+ }
+ sas->destroy(sas);
+
+ builder = vici_builder_create();
+ if (!found)
+ {
+ errmsg = "no matching SAs to redirect found";
+ }
+ builder->add_kv(builder, "success", errmsg ? "no" : "yes");
+ if (errmsg)
+ {
+ builder->add_kv(builder, "errmsg", "%s", errmsg);
+ }
+ gateway->destroy(gateway);
+ DESTROY_IF(identity);
+ DESTROY_IF(ts);
+ return builder->finalize(builder);
+}
+
+/**
* Find reqid of an existing CHILD_SA
*/
static u_int32_t find_reqid(child_cfg_t *cfg)
@@ -379,10 +544,11 @@ CALLBACK(install, vici_message_t*,
{
child_cfg_t *child_cfg = NULL;
peer_cfg_t *peer_cfg;
- char *child;
+ char *child, *ike;
bool ok;
child = request->get_str(request, NULL, "child");
+ ike = request->get_str(request, NULL, "ike");
if (!child)
{
return send_reply(this, "missing configuration name");
@@ -390,7 +556,7 @@ CALLBACK(install, vici_message_t*,
DBG1(DBG_CFG, "vici install '%s'", child);
- child_cfg = find_child_cfg(child, &peer_cfg);
+ child_cfg = find_child_cfg(child, ike, &peer_cfg);
if (!child_cfg)
{
return send_reply(this, "configuration name not found");
@@ -480,6 +646,7 @@ static void manage_commands(private_vici_control_t *this, bool reg)
{
manage_command(this, "initiate", initiate, reg);
manage_command(this, "terminate", terminate, reg);
+ manage_command(this, "redirect", redirect, reg);
manage_command(this, "install", install, reg);
manage_command(this, "uninstall", uninstall, reg);
manage_command(this, "reload-settings", reload_settings, reg);
diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c
index 6631184b5..3411b7d6c 100644
--- a/src/libcharon/plugins/vici/vici_cred.c
+++ b/src/libcharon/plugins/vici/vici_cred.c
@@ -2,6 +2,9 @@
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
+ * Copyright (C) 2015 Andreas Steffen
+ * HSR 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
@@ -15,6 +18,7 @@
#include "vici_cred.h"
#include "vici_builder.h"
+#include "vici_cert_info.h"
#include <credentials/sets/mem_cred.h>
#include <credentials/certificates/ac.h>
@@ -66,9 +70,9 @@ static vici_message_t* create_reply(char *fmt, ...)
CALLBACK(load_cert, vici_message_t*,
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
{
- certificate_type_t type;
- x509_flag_t required_flags = 0, additional_flags = 0;
certificate_t *cert;
+ certificate_type_t type;
+ x509_flag_t ext_flag, flag = X509_NONE;
x509_t *x509;
chunk_t data;
bool trusted = TRUE;
@@ -79,60 +83,55 @@ CALLBACK(load_cert, vici_message_t*,
{
return create_reply("certificate type missing");
}
- if (strcaseeq(str, "x509"))
- {
- type = CERT_X509;
- }
- else if (strcaseeq(str, "x509ca"))
- {
- type = CERT_X509;
- required_flags = X509_CA;
- }
- else if (strcaseeq(str, "x509aa"))
- {
- type = CERT_X509;
- additional_flags = X509_AA;
- }
- else if (strcaseeq(str, "x509crl"))
+ if (enum_from_name(certificate_type_names, str, &type))
{
- type = CERT_X509_CRL;
- }
- else if (strcaseeq(str, "x509ac"))
- {
- type = CERT_X509_AC;
- trusted = FALSE;
+ if (type == CERT_X509)
+ {
+ str = message->get_str(message, "NONE", "flag");
+ if (!enum_from_name(x509_flag_names, str, &flag))
+ {
+ return create_reply("invalid certificate flag '%s'", str);
+ }
+ }
}
- else
+ else if (!vici_cert_info_from_str(str, &type, &flag))
{
- return create_reply("invalid certificate type: %s", str);
+ return create_reply("invalid certificate type '%s'", str);
}
+
data = message->get_value(message, chunk_empty, "data");
if (!data.len)
{
return create_reply("certificate data missing");
}
+
+ /* do not set CA flag externally */
+ ext_flag = (flag & X509_CA) ? X509_NONE : flag;
+
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, type,
BUILD_BLOB_PEM, data,
- BUILD_X509_FLAG, additional_flags,
+ BUILD_X509_FLAG, ext_flag,
BUILD_END);
if (!cert)
{
return create_reply("parsing %N certificate failed",
certificate_type_names, type);
}
- if (cert->get_type(cert) == CERT_X509)
+ DBG1(DBG_CFG, "loaded certificate '%Y'", cert->get_subject(cert));
+
+ /* check if CA certificate has CA basic constraint set */
+ if (flag & X509_CA)
{
+ char err_msg[] = "ca certificate lacks CA basic constraint, rejected";
x509 = (x509_t*)cert;
- if ((required_flags & x509->get_flags(x509)) != required_flags)
+ if (!(x509->get_flags(x509) & X509_CA))
{
cert->destroy(cert);
- return create_reply("certificate misses required flag, rejected");
+ DBG1(DBG_CFG, " %s", err_msg);
+ return create_reply(err_msg);
}
}
-
- DBG1(DBG_CFG, "loaded certificate '%Y'", cert->get_subject(cert));
-
if (type == CERT_X509_CRL)
{
this->creds->add_crl(this->creds, (crl_t*)cert);
@@ -169,6 +168,10 @@ CALLBACK(load_key, vici_message_t*,
{
type = KEY_ECDSA;
}
+ else if (strcaseeq(str, "bliss"))
+ {
+ type = KEY_BLISS;
+ }
else
{
return create_reply("invalid key type: %s", str);
@@ -305,7 +308,7 @@ static void manage_commands(private_vici_cred_t *this, bool reg)
METHOD(vici_cred_t, add_cert, certificate_t*,
private_vici_cred_t *this, certificate_t *cert)
{
- return this->creds->get_cert_ref(this->creds, cert);
+ return this->creds->add_cert_ref(this->creds, TRUE, cert);
}
METHOD(vici_cred_t, destroy, void,
diff --git a/src/libcharon/plugins/vici/vici_plugin.c b/src/libcharon/plugins/vici/vici_plugin.c
index 53ed8cdfb..ed7c743c7 100644
--- a/src/libcharon/plugins/vici/vici_plugin.c
+++ b/src/libcharon/plugins/vici/vici_plugin.c
@@ -131,7 +131,8 @@ static bool register_vici(private_vici_plugin_t *this,
this->authority = vici_authority_create(this->dispatcher,
this->cred);
lib->credmgr->add_set(lib->credmgr, &this->authority->set);
- this->config = vici_config_create(this->dispatcher, this->authority);
+ this->config = vici_config_create(this->dispatcher, this->authority,
+ this->cred);
this->attrs = vici_attribute_create(this->dispatcher);
this->logger = vici_logger_create(this->dispatcher);
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index 9a3d832da..284c23ee0 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2015 Tobias Brunner, Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
@@ -37,6 +40,7 @@
#include "vici_query.h"
#include "vici_builder.h"
+#include "vici_cert_info.h"
#include <inttypes.h>
#include <time.h>
@@ -48,6 +52,9 @@
#endif
#include <daemon.h>
+#include <asn1/asn1.h>
+#include <credentials/certificates/certificate.h>
+#include <credentials/certificates/x509.h>
typedef struct private_vici_query_t private_vici_query_t;
@@ -120,7 +127,7 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
}
}
if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
- &alg, &ks) && alg != ENCR_UNDEFINED)
+ &alg, &ks) && alg != AUTH_UNDEFINED)
{
b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg);
if (ks)
@@ -128,11 +135,6 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
b->add_kv(b, "integ-keysize", "%u", ks);
}
}
- if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION,
- &alg, NULL))
- {
- b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg);
- }
if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
&alg, NULL))
{
@@ -271,15 +273,20 @@ static void list_ike(private_vici_query_t *this, vici_builder_t *b,
identification_t *eap;
proposal_t *proposal;
u_int16_t alg, ks;
+ host_t *host;
b->add_kv(b, "uniqueid", "%u", ike_sa->get_unique_id(ike_sa));
b->add_kv(b, "version", "%u", ike_sa->get_version(ike_sa));
b->add_kv(b, "state", "%N", ike_sa_state_names, ike_sa->get_state(ike_sa));
- b->add_kv(b, "local-host", "%H", ike_sa->get_my_host(ike_sa));
+ host = ike_sa->get_my_host(ike_sa);
+ b->add_kv(b, "local-host", "%H", host);
+ b->add_kv(b, "local-port", "%d", host->get_port(host));
b->add_kv(b, "local-id", "%Y", ike_sa->get_my_id(ike_sa));
- b->add_kv(b, "remote-host", "%H", ike_sa->get_other_host(ike_sa));
+ host = ike_sa->get_other_host(ike_sa);
+ b->add_kv(b, "remote-host", "%H", host);
+ b->add_kv(b, "remote-port", "%d", host->get_port(host));
b->add_kv(b, "remote-id", "%Y", ike_sa->get_other_id(ike_sa));
eap = ike_sa->get_other_eap_id(ike_sa);
@@ -301,8 +308,10 @@ static void list_ike(private_vici_query_t *this, vici_builder_t *b,
{
b->add_kv(b, "initiator", "yes");
}
- b->add_kv(b, "initiator-spi", "%.16"PRIx64, id->get_initiator_spi(id));
- b->add_kv(b, "responder-spi", "%.16"PRIx64, id->get_responder_spi(id));
+ b->add_kv(b, "initiator-spi", "%.16"PRIx64,
+ be64toh(id->get_initiator_spi(id)));
+ b->add_kv(b, "responder-spi", "%.16"PRIx64,
+ be64toh(id->get_responder_spi(id)));
add_condition(b, ike_sa, "nat-local", COND_NAT_HERE);
add_condition(b, ike_sa, "nat-remote", COND_NAT_THERE);
@@ -772,7 +781,7 @@ CALLBACK(list_conns, vici_message_t*,
/**
* Do we have a private key for given certificate
*/
-static bool has_privkey(private_vici_query_t *this, certificate_t *cert)
+static bool has_privkey(certificate_t *cert)
{
private_key_t *private;
public_key_t *public;
@@ -800,81 +809,332 @@ static bool has_privkey(private_vici_query_t *this, certificate_t *cert)
return found;
}
-CALLBACK(list_certs, vici_message_t*,
- private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
+/**
+ * Store cert filter data
+ */
+typedef struct {
+ certificate_type_t type;
+ x509_flag_t flag;
+ identification_t *subject;
+} cert_filter_t;
+
+/**
+ * Enumerate all X.509 certificates with a given flag
+ */
+static void enum_x509(private_vici_query_t *this, u_int id,
+ linked_list_t *certs, cert_filter_t *filter,
+ x509_flag_t flag)
{
- enumerator_t *enumerator, *added;
- linked_list_t *list;
- certificate_t *cert, *current;
- chunk_t encoding;
- identification_t *subject = NULL;
- int type;
+ enumerator_t *enumerator;
+ certificate_t *cert;
vici_builder_t *b;
- bool found;
- char *str;
+ chunk_t encoding;
+ x509_t *x509;
- str = request->get_str(request, "ANY", "type");
- if (!enum_from_name(certificate_type_names, str, &type))
+ if (filter->type != CERT_ANY && filter->flag != X509_ANY &&
+ filter->flag != flag)
{
- b = vici_builder_create();
- return b->finalize(b);
- }
- str = request->get_str(request, NULL, "subject");
- if (str)
- {
- subject = identification_create_from_string(str);
+ return;
}
- list = linked_list_create();
- enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
- type, KEY_ANY, subject, FALSE);
+ enumerator = certs->create_enumerator(certs);
while (enumerator->enumerate(enumerator, &cert))
{
- found = FALSE;
- added = list->create_enumerator(list);
- while (added->enumerate(added, &current))
+ x509 = (x509_t*)cert;
+ if ((x509->get_flags(x509) & X509_ANY) != flag)
{
- if (current->equals(current, cert))
+ continue;
+ }
+
+ if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
+ {
+ b = vici_builder_create();
+ b->add_kv(b, "type", "%N", certificate_type_names, CERT_X509);
+ b->add_kv(b, "flag", "%N", x509_flag_names, flag);
+ if (has_privkey(cert))
{
- found = TRUE;
- break;
+ b->add_kv(b, "has_privkey", "yes");
}
+ b->add(b, VICI_KEY_VALUE, "data", encoding);
+ free(encoding.ptr);
+
+ this->dispatcher->raise_event(this->dispatcher, "list-cert", id,
+ b->finalize(b));
}
- added->destroy(added);
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Enumerate all non-X.509 certificate types
+ */
+static void enum_others(private_vici_query_t *this, u_int id,
+ linked_list_t *certs, certificate_type_t type)
+{
+ enumerator_t *enumerator;
+ certificate_t *cert;
+ vici_builder_t *b;
+ chunk_t encoding, t_ch;
+ cred_encoding_type_t encoding_type;
+ identification_t *subject;
+ time_t not_before, not_after;
+
+ encoding_type = (type == CERT_TRUSTED_PUBKEY) ? PUBKEY_SPKI_ASN1_DER :
+ CERT_ASN1_DER;
- if (!found && cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
+ enumerator = certs->create_enumerator(certs);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ if (cert->get_encoding(cert, encoding_type, &encoding))
{
b = vici_builder_create();
- b->add_kv(b, "type", "%N",
- certificate_type_names, cert->get_type(cert));
- if (has_privkey(this, cert))
+ b->add_kv(b, "type", "%N", certificate_type_names, type);
+ if (has_privkey(cert))
{
b->add_kv(b, "has_privkey", "yes");
}
b->add(b, VICI_KEY_VALUE, "data", encoding);
free(encoding.ptr);
+ if (type == CERT_TRUSTED_PUBKEY)
+ {
+ subject = cert->get_subject(cert);
+ if (subject->get_type(subject) != ID_KEY_ID)
+ {
+ b->add_kv(b, "subject", "%Y", cert->get_subject(cert));
+ }
+ cert->get_validity(cert, NULL, &not_before, &not_after);
+ if (not_before != UNDEFINED_TIME)
+ {
+ t_ch = asn1_from_time(&not_before, ASN1_GENERALIZEDTIME);
+ b->add(b, VICI_KEY_VALUE, "not-before", chunk_skip(t_ch, 2));
+ chunk_free(&t_ch);
+ }
+ if (not_after != UNDEFINED_TIME)
+ {
+ t_ch = asn1_from_time(&not_after, ASN1_GENERALIZEDTIME);
+ b->add(b, VICI_KEY_VALUE, "not-after", chunk_skip(t_ch, 2));
+ chunk_free(&t_ch);
+ }
+ }
this->dispatcher->raise_event(this->dispatcher, "list-cert", id,
b->finalize(b));
- list->insert_last(list, cert->get_ref(cert));
}
}
enumerator->destroy(enumerator);
+}
- list->destroy_offset(list, offsetof(certificate_t, destroy));
- DESTROY_IF(subject);
+/**
+ * Enumerate all certificates of a given type
+ */
+static void enum_certs(private_vici_query_t *this, u_int id,
+ cert_filter_t *filter, certificate_type_t type)
+{
+ enumerator_t *e1, *e2;
+ certificate_t *cert, *current;
+ linked_list_t *certs;
+ bool found;
+ if (filter->type != CERT_ANY && filter->type != type)
+ {
+ return;
+ }
+ certs = linked_list_create();
+
+ e1 = lib->credmgr->create_cert_enumerator(lib->credmgr, type, KEY_ANY,
+ filter->subject, FALSE);
+ while (e1->enumerate(e1, &cert))
+ {
+ found = FALSE;
+
+ e2 = certs->create_enumerator(certs);
+ while (e2->enumerate(e2, &current))
+ {
+ if (current->equals(current, cert))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ e2->destroy(e2);
+
+ if (!found)
+ {
+ certs->insert_last(certs, cert->get_ref(cert));
+ }
+ }
+ e1->destroy(e1);
+
+ if (type == CERT_X509)
+ {
+ enum_x509(this, id, certs, filter, X509_NONE);
+ enum_x509(this, id, certs, filter, X509_CA);
+ enum_x509(this, id, certs, filter, X509_AA);
+ enum_x509(this, id, certs, filter, X509_OCSP_SIGNER);
+ }
+ else
+ {
+ enum_others(this, id, certs, type);
+ }
+ certs->destroy_offset(certs, offsetof(certificate_t, destroy));
+}
+
+CALLBACK(list_certs, vici_message_t*,
+ private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
+{
+ cert_filter_t filter = {
+ .type = CERT_ANY,
+ .flag = X509_ANY,
+ .subject = NULL
+ };
+ vici_builder_t *b;
+ char *str;
+
+ str = request->get_str(request, "ANY", "type");
+ if (enum_from_name(certificate_type_names, str, &filter.type))
+ {
+ if (filter.type == CERT_X509)
+ {
+ str = request->get_str(request, "ANY", "flag");
+ if (!enum_from_name(x509_flag_names, str, &filter.flag))
+ {
+ DBG1(DBG_CFG, "invalid certificate flag '%s'", str);
+ goto finalize;
+ }
+ }
+ }
+ else if (!vici_cert_info_from_str(str, &filter.type, &filter.flag))
+ {
+ DBG1(DBG_CFG, "invalid certificate type '%s'", str);
+ goto finalize;
+ }
+
+ str = request->get_str(request, NULL, "subject");
+ if (str)
+ {
+ filter.subject = identification_create_from_string(str);
+ }
+
+ enum_certs(this, id, &filter, CERT_TRUSTED_PUBKEY);
+ enum_certs(this, id, &filter, CERT_X509);
+ enum_certs(this, id, &filter, CERT_X509_AC);
+ enum_certs(this, id, &filter, CERT_X509_CRL);
+ enum_certs(this, id, &filter, CERT_X509_OCSP_RESPONSE);
+ DESTROY_IF(filter.subject);
+
+finalize:
b = vici_builder_create();
return b->finalize(b);
}
-CALLBACK(version, vici_message_t*,
+/**
+ * Add a key/value pair of ALG => plugin
+ */
+static void add_algorithm(vici_builder_t *b, enum_name_t *alg_names,
+ int alg_type, const char *plugin_name)
+{
+ char alg_name[BUF_LEN];
+
+ sprintf(alg_name, "%N", alg_names, alg_type);
+ b->add_kv(b, alg_name, (char*)plugin_name);
+}
+
+CALLBACK(get_algorithms, vici_message_t*,
private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
{
vici_builder_t *b;
+ enumerator_t *enumerator;
+ encryption_algorithm_t encryption;
+ integrity_algorithm_t integrity;
+ hash_algorithm_t hash;
+ pseudo_random_function_t prf;
+ diffie_hellman_group_t group;
+ rng_quality_t quality;
+ const char *plugin_name;
b = vici_builder_create();
+ b->begin_section(b, "encryption");
+ enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+ {
+ add_algorithm(b, encryption_algorithm_names, encryption, plugin_name);
+ }
+ enumerator->destroy(enumerator);
+ b->end_section(b);
+
+ b->begin_section(b, "integrity");
+ enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
+ {
+ add_algorithm(b, integrity_algorithm_names, integrity, plugin_name);
+ }
+ enumerator->destroy(enumerator);
+ b->end_section(b);
+
+ b->begin_section(b, "aead");
+ enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+ {
+ add_algorithm(b, encryption_algorithm_names, encryption, plugin_name);
+ }
+ enumerator->destroy(enumerator);
+ b->end_section(b);
+
+ b->begin_section(b, "hasher");
+ enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &hash, &plugin_name))
+ {
+ add_algorithm(b, hash_algorithm_names, hash, plugin_name);
+ }
+ enumerator->destroy(enumerator);
+ b->end_section(b);
+
+ b->begin_section(b, "prf");
+ enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &prf, &plugin_name))
+ {
+ add_algorithm(b, pseudo_random_function_names, prf, plugin_name);
+ }
+ enumerator->destroy(enumerator);
+ b->end_section(b);
+
+ b->begin_section(b, "dh");
+ enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &group, &plugin_name))
+ {
+ add_algorithm(b, diffie_hellman_group_names, group, plugin_name);
+ }
+ enumerator->destroy(enumerator);
+ b->end_section(b);
+
+ b->begin_section(b, "rng");
+ enumerator = lib->crypto->create_rng_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &quality, &plugin_name))
+ {
+ add_algorithm(b, rng_quality_names, quality, plugin_name);
+ }
+ enumerator->destroy(enumerator);
+ b->end_section(b);
+
+ b->begin_section(b, "nonce-gen");
+ enumerator = lib->crypto->create_nonce_gen_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &plugin_name))
+ {
+ b->add_kv(b, "NONCE_GEN", (char*)plugin_name);
+ }
+ enumerator->destroy(enumerator);
+ b->end_section(b);
+
+ return b->finalize(b);
+}
+
+CALLBACK(version, vici_message_t*,
+ private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
+{
+ vici_builder_t *b;
+
+ b = vici_builder_create();
b->add_kv(b, "daemon", "%s", lib->ns);
b->add_kv(b, "version", "%s", VERSION);
@@ -915,18 +1175,6 @@ CALLBACK(version, vici_message_t*,
return b->finalize(b);
}
-/**
- * Callback function for memusage summary
- */
-CALLBACK(sum_usage, void,
- vici_builder_t *b, int count, size_t bytes, int whitelisted)
-{
- b->begin_section(b, "mem");
- b->add_kv(b, "total", "%zu", bytes);
- b->add_kv(b, "allocs", "%d", count);
- b->end_section(b);
-}
-
CALLBACK(stats, vici_message_t*,
private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
{
@@ -988,12 +1236,7 @@ CALLBACK(stats, vici_message_t*,
enumerator->destroy(enumerator);
b->end_list(b);
- if (lib->leak_detective)
- {
- lib->leak_detective->usage(lib->leak_detective, NULL, sum_usage, b);
- }
#ifdef WIN32
- else
{
DWORD lasterr = ERROR_INVALID_HANDLE;
HANDLE heaps[32];
@@ -1085,6 +1328,7 @@ static void manage_commands(private_vici_query_t *this, bool reg)
manage_command(this, "list-policies", list_policies, reg);
manage_command(this, "list-conns", list_conns, reg);
manage_command(this, "list-certs", list_certs, reg);
+ manage_command(this, "get-algorithms", get_algorithms, reg);
manage_command(this, "version", version, reg);
manage_command(this, "stats", stats, reg);
}
diff --git a/src/libcharon/plugins/vici/vici_tests.c b/src/libcharon/plugins/vici/vici_tests.c
index 434aa5e18..d1f8097bf 100644
--- a/src/libcharon/plugins/vici/vici_tests.c
+++ b/src/libcharon/plugins/vici/vici_tests.c
@@ -16,7 +16,6 @@
#include <test_runner.h>
#include <daemon.h>
-#include <hydra.h>
/* declare test suite constructors */
#define TEST_SUITE(x) test_suite_t* x();