summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/vici
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/vici')
-rw-r--r--src/libcharon/plugins/vici/Makefile.am4
-rw-r--r--src/libcharon/plugins/vici/Makefile.in10
-rw-r--r--src/libcharon/plugins/vici/README.md97
-rw-r--r--src/libcharon/plugins/vici/libvici.c8
-rw-r--r--src/libcharon/plugins/vici/python/LICENSE19
-rw-r--r--src/libcharon/plugins/vici/python/MANIFEST.in1
-rw-r--r--src/libcharon/plugins/vici/python/Makefile.am33
-rw-r--r--src/libcharon/plugins/vici/python/Makefile.in686
-rw-r--r--src/libcharon/plugins/vici/python/setup.py.in34
-rw-r--r--src/libcharon/plugins/vici/python/vici/__init__.py1
-rw-r--r--src/libcharon/plugins/vici/python/vici/compat.py14
-rw-r--r--src/libcharon/plugins/vici/python/vici/exception.py10
-rw-r--r--src/libcharon/plugins/vici/python/vici/protocol.py196
-rw-r--r--src/libcharon/plugins/vici/python/vici/session.py327
-rw-r--r--src/libcharon/plugins/vici/python/vici/test/__init__.py0
-rw-r--r--src/libcharon/plugins/vici/python/vici/test/test_protocol.py144
-rw-r--r--src/libcharon/plugins/vici/ruby/Makefile.am6
-rw-r--r--src/libcharon/plugins/vici/ruby/Makefile.in11
-rw-r--r--src/libcharon/plugins/vici/ruby/lib/vici.rb30
-rw-r--r--src/libcharon/plugins/vici/ruby/vici.gemspec.in2
-rw-r--r--src/libcharon/plugins/vici/vici_attribute.c67
-rw-r--r--src/libcharon/plugins/vici/vici_builder.c79
-rw-r--r--src/libcharon/plugins/vici/vici_builder.h8
-rw-r--r--src/libcharon/plugins/vici/vici_config.c51
-rw-r--r--src/libcharon/plugins/vici/vici_control.c4
-rw-r--r--src/libcharon/plugins/vici/vici_plugin.c9
-rw-r--r--src/libcharon/plugins/vici/vici_query.c17
27 files changed, 1771 insertions, 97 deletions
diff --git a/src/libcharon/plugins/vici/Makefile.am b/src/libcharon/plugins/vici/Makefile.am
index da71de394..b25396085 100644
--- a/src/libcharon/plugins/vici/Makefile.am
+++ b/src/libcharon/plugins/vici/Makefile.am
@@ -74,3 +74,7 @@ SUBDIRS =
if USE_RUBY_GEMS
SUBDIRS += ruby
endif
+
+if USE_PYTHON_EGGS
+SUBDIRS += python
+endif
diff --git a/src/libcharon/plugins/vici/Makefile.in b/src/libcharon/plugins/vici/Makefile.in
index 34546b905..b63226daa 100644
--- a/src/libcharon/plugins/vici/Makefile.in
+++ b/src/libcharon/plugins/vici/Makefile.in
@@ -81,6 +81,7 @@ host_triplet = @host@
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
subdir = src/libcharon/plugins/vici
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/depcomp
@@ -269,7 +270,7 @@ am__tty_colors = { \
std=''; \
fi; \
}
-DIST_SUBDIRS = ruby
+DIST_SUBDIRS = ruby python
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
@@ -321,6 +322,7 @@ DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
+EASY_INSTALL = @EASY_INSTALL@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
@@ -381,10 +383,12 @@ 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@
@@ -458,6 +462,8 @@ 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@
@@ -571,7 +577,7 @@ vici_tests_LDADD = \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(top_builddir)/src/libstrongswan/tests/libtest.la
-SUBDIRS = $(am__append_1)
+SUBDIRS = $(am__append_1) $(am__append_2)
all: all-recursive
.SUFFIXES:
diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
index 272491052..0ce4271b0 100644
--- a/src/libcharon/plugins/vici/README.md
+++ b/src/libcharon/plugins/vici/README.md
@@ -145,25 +145,25 @@ the following C array:
char msg[] = {
/* key1 = value1 */
- 2, 4,'k','e','y','1', 0,6,'v','a','l','u','e','1',
+ 3, 4,'k','e','y','1', 0,6,'v','a','l','u','e','1',
/* section1 */
- 0, 8,'s','e','c','t','i','o','n','1',
+ 1, 8,'s','e','c','t','i','o','n','1',
/* sub-section */
- 0, 11,'s','u','b','-','s','e','c','t','i','o','n',
+ 1, 11,'s','u','b','-','s','e','c','t','i','o','n',
/* key2 = value2 */
- 2, 4,'k','e','y','2', 0,6,'v','a','l','u','e','2',
+ 3, 4,'k','e','y','2', 0,6,'v','a','l','u','e','2',
/* sub-section end */
- 1,
+ 2,
/* list1 */
- 3, 5, 'l','i','s','t','1',
+ 4, 5, 'l','i','s','t','1',
/* item1 */
- 4, 0,5,'i','t','e','m','1',
+ 5, 0,5,'i','t','e','m','1',
/* item2 */
- 4, 0,5,'i','t','e','m','2',
+ 5, 0,5,'i','t','e','m','2',
/* list1 end */
- 5,
+ 6,
/* section1 end */
- 1,
+ 2,
};
## Client-initiated commands ##
@@ -559,6 +559,7 @@ command.
]
child-sas = {
<child-sa-name>* = {
+ uniqueid = <unique CHILD_SA identifier>
reqid = <reqid of CHILD_SA>
state = <state string of CHILD_SA>
mode = <IPsec mode, tunnel|transport|beet>
@@ -820,9 +821,9 @@ during encoding.
## Connecting to the daemon ##
-To create a connection to the daemon, a socket must be passed to the
-_Connection_ constructor. There is no default, but on Unix systems usually
-a Unix socket over _/var/run/charon.vici_ is used:
+To create a connection to the daemon, a socket can be passed to the
+_Connection_ constructor. If none is passed, a default Unix socket at
+_/var/run/charon.vici_ is used:
require "vici"
require "socket"
@@ -854,3 +855,73 @@ _list-conns_ command and implicitly the _list-conn_ event:
For more details about the ruby gem refer to the comments in the gem source
code or the generated documentation.
+
+# vici Python egg #
+
+The _vici Python egg_ is a pure Python implementation of the VICI protocol to
+implement client applications. It is provided in the _python_ subdirectory, and
+gets built and installed if strongSwan has been _./configure_'d with
+_--enable-vici_ and _--enable-python-eggs_.
+
+The _vici_ module provides a _Session()_ constructor for a high level interface,
+the underlying classes are usually not required to build Python applications
+using VICI. The _Session_ class provides methods for the supported VICI
+commands.
+
+To represent the VICI message data tree, the library converts the binary
+encoding to Python data types. The _Session_ class takes and returns Python
+objects for the exchanged message data:
+ * Sections get encoded as OrderedDict, containing other sections, or
+ * Key/Values, where the values are strings as dictionary values
+ * Lists get encoded as Python Lists with string values
+Values that do not conform to Python dict or list get converted to strings using
+str().
+
+## Connecting to the daemon ##
+
+To create a connection to the daemon, a socket can be passed to the _Session_
+constructor. If none is passed, a default Unix socket at _/var/run/charon.vici_
+is used:
+
+ import vici
+ import socket
+
+ s = socket.socket(socket.AF_UNIX)
+ s.connect("/var/run/charon.vici")
+ v = vici.Session(s)
+
+## A simple client request ##
+
+An example to print the daemon version information is as simple as:
+
+ ver = v.version()
+
+ print "{daemon} {version} ({sysname}, {release}, {machine})".format(**ver)
+
+## A request with response iteration ##
+
+The _Session_ class returns an iterable Python generator for streamed events to
+continuously stream objects to the caller. The following example lists all
+loaded connections using the _list-conns_ command and implicitly the _list-conn_
+event:
+
+ for conn in v.list_conns():
+ for key in conn:
+ print key
+
+Please note that if the returned generator is not iterated completely, it must
+be closed using _close()_. This is implicitly done when breaking from a loop,
+but an explicit call may be required when directly iterating the generator with
+_next()_.
+
+## Sorting in dictionaries ##
+
+In VICI, in some message trees the order of objects in dictionary matters. In
+contrast to ruby Hashes, Python dictionaries do not preserve order of added
+objects. It is therefore recommended to use OrderedDicts instead of the default
+dictionaries. Objects returned by the library use OrderedDicts.
+
+## API documentation ##
+
+For more details about the Python egg refer to the comments in the Python source
+code.
diff --git a/src/libcharon/plugins/vici/libvici.c b/src/libcharon/plugins/vici/libvici.c
index c0205ccb6..7c98c8b69 100644
--- a/src/libcharon/plugins/vici/libvici.c
+++ b/src/libcharon/plugins/vici/libvici.c
@@ -427,14 +427,8 @@ vici_res_t* vici_submit(vici_req_t *req, vici_conn_t *conn)
void vici_free_req(vici_req_t *req)
{
- vici_message_t *message;
-
free(req->name);
- message = req->b->finalize(req->b);
- if (message)
- {
- message->destroy(message);
- }
+ req->b->destroy(req->b);
free(req);
}
diff --git a/src/libcharon/plugins/vici/python/LICENSE b/src/libcharon/plugins/vici/python/LICENSE
new file mode 100644
index 000000000..111523ca8
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Björn Schuberg
+
+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/python/MANIFEST.in b/src/libcharon/plugins/vici/python/MANIFEST.in
new file mode 100644
index 000000000..1aba38f67
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/MANIFEST.in
@@ -0,0 +1 @@
+include LICENSE
diff --git a/src/libcharon/plugins/vici/python/Makefile.am b/src/libcharon/plugins/vici/python/Makefile.am
new file mode 100644
index 000000000..f51737870
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/Makefile.am
@@ -0,0 +1,33 @@
+EXTRA_DIST = LICENSE MANIFEST.in \
+ setup.py.in \
+ vici/test/__init__.py \
+ vici/test/test_protocol.py \
+ vici/__init__.py \
+ vici/compat.py \
+ vici/exception.py \
+ vici/protocol.py \
+ vici/session.py
+
+setup.py: $(srcdir)/setup.py.in
+ $(AM_V_GEN) sed \
+ -e "s:@EGG_VERSION@:$(PACKAGE_VERSION):" \
+ $(srcdir)/setup.py.in > $@
+
+all-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+
+dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg: $(EXTRA_DIST) setup.py
+ (cd $(srcdir); $(PYTHON) setup.py bdist_egg \
+ -b $(shell readlink -f $(builddir))/build \
+ -d $(shell readlink -f $(builddir))/dist)
+
+clean-local: setup.py
+ $(PYTHON) setup.py clean -a
+ rm -rf vici.egg-info dist setup.py
+
+install-exec-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+ $(EASY_INSTALL) $(PYTHONEGGINSTALLDIR) \
+ dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+
+if USE_PY_TEST
+ TESTS = $(PY_TEST)
+endif
diff --git a/src/libcharon/plugins/vici/python/Makefile.in b/src/libcharon/plugins/vici/python/Makefile.in
new file mode 100644
index 000000000..3a5e5ea72
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/Makefile.in
@@ -0,0 +1,686 @@
+# 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/python
+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)
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+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_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 = LICENSE MANIFEST.in \
+ setup.py.in \
+ vici/test/__init__.py \
+ vici/test/test_protocol.py \
+ vici/__init__.py \
+ vici/compat.py \
+ vici/exception.py \
+ vici/protocol.py \
+ vici/session.py
+
+@USE_PY_TEST_TRUE@TESTS = $(PY_TEST)
+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/python/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libcharon/plugins/vici/python/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:
+
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+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
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+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."
+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: check-am install-am install-strip
+
+.PHONY: all all-am all-local check check-TESTS 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
+
+
+setup.py: $(srcdir)/setup.py.in
+ $(AM_V_GEN) sed \
+ -e "s:@EGG_VERSION@:$(PACKAGE_VERSION):" \
+ $(srcdir)/setup.py.in > $@
+
+all-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+
+dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg: $(EXTRA_DIST) setup.py
+ (cd $(srcdir); $(PYTHON) setup.py bdist_egg \
+ -b $(shell readlink -f $(builddir))/build \
+ -d $(shell readlink -f $(builddir))/dist)
+
+clean-local: setup.py
+ $(PYTHON) setup.py clean -a
+ rm -rf vici.egg-info dist setup.py
+
+install-exec-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+ $(EASY_INSTALL) $(PYTHONEGGINSTALLDIR) \
+ dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+
+# 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/python/setup.py.in b/src/libcharon/plugins/vici/python/setup.py.in
new file mode 100644
index 000000000..0e4ad8236
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/setup.py.in
@@ -0,0 +1,34 @@
+from setuptools import setup
+
+
+long_description = (
+ "The strongSwan VICI protocol allows external application to monitor, "
+ "configure and control the IKE daemon charon. This python package provides "
+ "a native client side implementation of the VICI protocol, well suited to "
+ "script automated tasks in a reliable way."
+)
+
+setup(
+ name="vici",
+ version="@EGG_VERSION@",
+ description="Native python interface for strongSwan VICI",
+ author="Bjorn Schuberg",
+ url="https://wiki.strongswan.org/projects/strongswan/wiki/Vici",
+ license="MIT",
+ packages=["vici"],
+ long_description=long_description,
+ include_package_data=True,
+ classifiers=(
+ "Development Status :: 3 - Alpha",
+ "Intended Audience :: Developers",
+ "Intended Audience :: System Administrators",
+ "License :: OSI Approved :: MIT License",
+ "Natural Language :: English",
+ "Programming Language :: Python :: 2.7",
+ "Programming Language :: Python :: 3.2",
+ "Programming Language :: Python :: 3.3",
+ "Programming Language :: Python :: 3.4",
+ "Topic :: Security",
+ "Topic :: Software Development :: Libraries",
+ )
+)
diff --git a/src/libcharon/plugins/vici/python/vici/__init__.py b/src/libcharon/plugins/vici/python/vici/__init__.py
new file mode 100644
index 000000000..d314325b6
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/vici/__init__.py
@@ -0,0 +1 @@
+from .session import Session
diff --git a/src/libcharon/plugins/vici/python/vici/compat.py b/src/libcharon/plugins/vici/python/vici/compat.py
new file mode 100644
index 000000000..b5f46992e
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/vici/compat.py
@@ -0,0 +1,14 @@
+# Help functions for compatibility between python version 2 and 3
+
+
+# From http://legacy.python.org/dev/peps/pep-0469
+try:
+ dict.iteritems
+except AttributeError:
+ # python 3
+ def iteritems(d):
+ return iter(d.items())
+else:
+ # python 2
+ def iteritems(d):
+ return d.iteritems()
diff --git a/src/libcharon/plugins/vici/python/vici/exception.py b/src/libcharon/plugins/vici/python/vici/exception.py
new file mode 100644
index 000000000..36384e556
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/vici/exception.py
@@ -0,0 +1,10 @@
+"""Exception types that may be thrown by this library."""
+
+class DeserializationException(Exception):
+ """Encountered an unexpected byte sequence or missing element type."""
+
+class SessionException(Exception):
+ """Session request exception."""
+
+class CommandException(Exception):
+ """Command result exception."""
diff --git a/src/libcharon/plugins/vici/python/vici/protocol.py b/src/libcharon/plugins/vici/python/vici/protocol.py
new file mode 100644
index 000000000..855a7b2e2
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/vici/protocol.py
@@ -0,0 +1,196 @@
+import io
+import socket
+import struct
+
+from collections import namedtuple
+from collections import OrderedDict
+
+from .compat import iteritems
+from .exception import DeserializationException
+
+
+class Transport(object):
+ HEADER_LENGTH = 4
+ MAX_SEGMENT = 512 * 1024
+
+ def __init__(self, sock):
+ self.socket = sock
+
+ def send(self, packet):
+ self.socket.sendall(struct.pack("!I", len(packet)) + packet)
+
+ def receive(self):
+ raw_length = self.socket.recv(self.HEADER_LENGTH)
+ length, = struct.unpack("!I", raw_length)
+ payload = self.socket.recv(length)
+ return payload
+
+ def close(self):
+ self.socket.shutdown(socket.SHUT_RDWR)
+ self.socket.close()
+
+
+class Packet(object):
+ 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
+
+ ParsedPacket = namedtuple(
+ "ParsedPacket",
+ ["response_type", "payload"]
+ )
+
+ ParsedEventPacket = namedtuple(
+ "ParsedEventPacket",
+ ["response_type", "event_type", "payload"]
+ )
+
+ @classmethod
+ def _named_request(cls, request_type, request, message=None):
+ request = request.encode()
+ payload = struct.pack("!BB", request_type, len(request)) + request
+ if message is not None:
+ return payload + message
+ else:
+ return payload
+
+ @classmethod
+ def request(cls, command, message=None):
+ return cls._named_request(cls.CMD_REQUEST, command, message)
+
+ @classmethod
+ def register_event(cls, event_type):
+ return cls._named_request(cls.EVENT_REGISTER, event_type)
+
+ @classmethod
+ def unregister_event(cls, event_type):
+ return cls._named_request(cls.EVENT_UNREGISTER, event_type)
+
+ @classmethod
+ def parse(cls, packet):
+ stream = FiniteStream(packet)
+ response_type, = struct.unpack("!B", stream.read(1))
+
+ if response_type == cls.EVENT:
+ length, = struct.unpack("!B", stream.read(1))
+ event_type = stream.read(length)
+ return cls.ParsedEventPacket(response_type, event_type, stream)
+ else:
+ return cls.ParsedPacket(response_type, stream)
+
+
+class Message(object):
+ 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
+
+ @classmethod
+ def serialize(cls, message):
+ def encode_named_type(marker, name):
+ name = name.encode()
+ return struct.pack("!BB", marker, len(name)) + name
+
+ def encode_blob(value):
+ if not isinstance(value, bytes):
+ value = str(value).encode()
+ return struct.pack("!H", len(value)) + value
+
+ def serialize_list(lst):
+ segment = bytes()
+ for item in lst:
+ segment += struct.pack("!B", cls.LIST_ITEM) + encode_blob(item)
+ return segment
+
+ def serialize_dict(d):
+ segment = bytes()
+ for key, value in iteritems(d):
+ if isinstance(value, dict):
+ segment += (
+ encode_named_type(cls.SECTION_START, key)
+ + serialize_dict(value)
+ + struct.pack("!B", cls.SECTION_END)
+ )
+ elif isinstance(value, list):
+ segment += (
+ encode_named_type(cls.LIST_START, key)
+ + serialize_list(value)
+ + struct.pack("!B", cls.LIST_END)
+ )
+ else:
+ segment += (
+ encode_named_type(cls.KEY_VALUE, key)
+ + encode_blob(value)
+ )
+ return segment
+
+ return serialize_dict(message)
+
+ @classmethod
+ def deserialize(cls, stream):
+ def decode_named_type(stream):
+ length, = struct.unpack("!B", stream.read(1))
+ return stream.read(length).decode()
+
+ def decode_blob(stream):
+ length, = struct.unpack("!H", stream.read(2))
+ return stream.read(length)
+
+ def decode_list_item(stream):
+ marker, = struct.unpack("!B", stream.read(1))
+ while marker == cls.LIST_ITEM:
+ yield decode_blob(stream)
+ marker, = struct.unpack("!B", stream.read(1))
+
+ if marker != cls.LIST_END:
+ raise DeserializationException(
+ "Expected end of list at {pos}".format(pos=stream.tell())
+ )
+
+ section = OrderedDict()
+ section_stack = []
+ while stream.has_more():
+ element_type, = struct.unpack("!B", stream.read(1))
+ if element_type == cls.SECTION_START:
+ section_name = decode_named_type(stream)
+ new_section = OrderedDict()
+ section[section_name] = new_section
+ section_stack.append(section)
+ section = new_section
+
+ elif element_type == cls.LIST_START:
+ list_name = decode_named_type(stream)
+ section[list_name] = [item for item in decode_list_item(stream)]
+
+ elif element_type == cls.KEY_VALUE:
+ key = decode_named_type(stream)
+ section[key] = decode_blob(stream)
+
+ elif element_type == cls.SECTION_END:
+ if len(section_stack):
+ section = section_stack.pop()
+ else:
+ raise DeserializationException(
+ "Unexpected end of section at {pos}".format(
+ pos=stream.tell()
+ )
+ )
+
+ if len(section_stack):
+ raise DeserializationException("Expected end of section")
+ return section
+
+
+class FiniteStream(io.BytesIO):
+ def __len__(self):
+ return len(self.getvalue())
+
+ def has_more(self):
+ return self.tell() < len(self)
diff --git a/src/libcharon/plugins/vici/python/vici/session.py b/src/libcharon/plugins/vici/python/vici/session.py
new file mode 100644
index 000000000..dee58699d
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/vici/session.py
@@ -0,0 +1,327 @@
+import collections
+import socket
+
+from .exception import SessionException, CommandException
+from .protocol import Transport, Packet, Message
+
+
+class Session(object):
+ def __init__(self, sock=None):
+ if sock is None:
+ sock = socket.socket(socket.AF_UNIX)
+ sock.connect("/var/run/charon.vici")
+ self.handler = SessionHandler(Transport(sock))
+
+ def version(self):
+ """Retrieve daemon and system specific version information.
+
+ :return: daemon and system specific version information
+ :rtype: dict
+ """
+ return self.handler.request("version")
+
+ def stats(self):
+ """Retrieve IKE daemon statistics and load information.
+
+ :return: IKE daemon statistics and load information
+ :rtype: dict
+ """
+ return self.handler.request("stats")
+
+ def reload_settings(self):
+ """Reload strongswan.conf settings and any plugins supporting reload.
+ """
+ self.handler.request("reload-settings")
+
+ def initiate(self, sa):
+ """Initiate an SA.
+
+ :param sa: the SA to initiate
+ :type sa: dict
+ :return: generator for logs emitted as dict
+ :rtype: generator
+ """
+ return self.handler.streamed_request("initiate", "control-log", sa)
+
+ def terminate(self, sa):
+ """Terminate an SA.
+
+ :param sa: the SA to terminate
+ :type sa: dict
+ :return: generator for logs emitted as dict
+ :rtype: generator
+ """
+ return self.handler.streamed_request("terminate", "control-log", sa)
+
+ def install(self, policy):
+ """Install a trap, drop or bypass policy defined by a CHILD_SA config.
+
+ :param policy: policy to install
+ :type policy: dict
+ """
+ self.handler.request("install", policy)
+
+ def uninstall(self, policy):
+ """Uninstall a trap, drop or bypass policy defined by a CHILD_SA config.
+
+ :param policy: policy to uninstall
+ :type policy: dict
+ """
+ self.handler.request("uninstall", policy)
+
+ def list_sas(self, filters=None):
+ """Retrieve active IKE_SAs and associated CHILD_SAs.
+
+ :param filters: retrieve only matching IKE_SAs (optional)
+ :type filters: dict
+ :return: generator for active IKE_SAs and associated CHILD_SAs as dict
+ :rtype: generator
+ """
+ return self.handler.streamed_request("list-sas", "list-sa", filters)
+
+ def list_policies(self, filters=None):
+ """Retrieve installed trap, drop and bypass policies.
+
+ :param filters: retrieve only matching policies (optional)
+ :type filters: dict
+ :return: generator for installed trap, drop and bypass policies as dict
+ :rtype: generator
+ """
+ return self.handler.streamed_request("list-policies", "list-policy",
+ filters)
+
+ def list_conns(self, filters=None):
+ """Retrieve loaded connections.
+
+ :param filters: retrieve only matching configuration names (optional)
+ :type filters: dict
+ :return: generator for loaded connections as dict
+ :rtype: generator
+ """
+ return self.handler.streamed_request("list-conns", "list-conn",
+ filters)
+
+ def get_conns(self):
+ """Retrieve connection names loaded exclusively over vici.
+
+ :return: connection names
+ :rtype: dict
+ """
+ return self.handler.request("get-conns")
+
+ def list_certs(self, filters=None):
+ """Retrieve loaded certificates.
+
+ :param filters: retrieve only matching certificates (optional)
+ :type filters: dict
+ :return: generator for loaded certificates as dict
+ :rtype: generator
+ """
+ return self.handler.streamed_request("list-certs", "list-cert", filters)
+
+ def load_conn(self, connection):
+ """Load a connection definition into the daemon.
+
+ :param connection: connection definition
+ :type connection: dict
+ """
+ self.handler.request("load-conn", connection)
+
+ def unload_conn(self, name):
+ """Unload a connection definition.
+
+ :param name: connection definition name
+ :type name: dict
+ """
+ self.handler.request("unload-conn", name)
+
+ def load_cert(self, certificate):
+ """Load a certificate into the daemon.
+
+ :param certificate: PEM or DER encoded certificate
+ :type certificate: dict
+ """
+ self.handler.request("load-cert", certificate)
+
+ def load_key(self, private_key):
+ """Load a private key into the daemon.
+
+ :param private_key: PEM or DER encoded key
+ """
+ self.handler.request("load-key", private_key)
+
+ def load_shared(self, secret):
+ """Load a shared IKE PSK, EAP or XAuth secret into the daemon.
+
+ :param secret: shared IKE PSK, EAP or XAuth secret
+ :type secret: dict
+ """
+ self.handler.request("load-shared", secret)
+
+ def clear_creds(self):
+ """Clear credentials loaded over vici.
+
+ Clear all loaded certificate, private key and shared key credentials.
+ This affects only credentials loaded over vici, but additionally
+ flushes the credential cache.
+ """
+ self.handler.request("clear-creds")
+
+ def load_pool(self, pool):
+ """Load a virtual IP pool.
+
+ Load an in-memory virtual IP and configuration attribute pool.
+ Existing pools with the same name get updated, if possible.
+
+ :param pool: virtual IP and configuration attribute pool
+ :type pool: dict
+ """
+ return self.handler.request("load-pool", pool)
+
+ def unload_pool(self, pool_name):
+ """Unload a virtual IP pool.
+
+ Unload a previously loaded virtual IP and configuration attribute pool.
+ Unloading fails for pools with leases currently online.
+
+ :param pool_name: pool by name
+ :type pool_name: dict
+ """
+ self.handler.request("unload-pool", pool_name)
+
+ def get_pools(self):
+ """Retrieve loaded pools.
+
+ :return: loaded pools
+ :rtype: dict
+ """
+ return self.handler.request("get-pools")
+
+
+class SessionHandler(object):
+ """Handles client command execution requests over vici."""
+
+ def __init__(self, transport):
+ self.transport = transport
+
+ def _communicate(self, packet):
+ """Send packet over transport and parse response.
+
+ :param packet: packet to send
+ :type packet: :py:class:`vici.protocol.Packet`
+ :return: parsed packet in a tuple with message type and payload
+ :rtype: :py:class:`collections.namedtuple`
+ """
+ self.transport.send(packet)
+ return Packet.parse(self.transport.receive())
+
+ def request(self, command, message=None):
+ """Send request with an optional message.
+
+ :param command: command to send
+ :type command: str
+ :param message: message (optional)
+ :type message: str
+ :return: command result
+ :rtype: dict
+ """
+ if message is not None:
+ message = Message.serialize(message)
+ packet = Packet.request(command, message)
+ response = self._communicate(packet)
+
+ if response.response_type != Packet.CMD_RESPONSE:
+ raise SessionException(
+ "Unexpected response type {type}, "
+ "expected '{response}' (CMD_RESPONSE)".format(
+ type=response.response_type,
+ response=Packet.CMD_RESPONSE
+ )
+ )
+
+ command_response = Message.deserialize(response.payload)
+ if "success" in command_response:
+ if command_response["success"] != b"yes":
+ raise CommandException(
+ "Command failed: {errmsg}".format(
+ errmsg=command_response["errmsg"]
+ )
+ )
+
+ return command_response
+
+ def streamed_request(self, command, event_stream_type, message=None):
+ """Send command request and collect and return all emitted events.
+
+ :param command: command to send
+ :type command: str
+ :param event_stream_type: event type emitted on command execution
+ :type event_stream_type: str
+ :param message: message (optional)
+ :type message: str
+ :return: generator for streamed event responses as dict
+ :rtype: generator
+ """
+ if message is not None:
+ message = Message.serialize(message)
+
+ # subscribe to event stream
+ packet = Packet.register_event(event_stream_type)
+ response = self._communicate(packet)
+
+ if response.response_type != Packet.EVENT_CONFIRM:
+ raise SessionException(
+ "Unexpected response type {type}, "
+ "expected '{confirm}' (EVENT_CONFIRM)".format(
+ type=response.response_type,
+ confirm=Packet.EVENT_CONFIRM,
+ )
+ )
+
+ # issue command, and read any event messages
+ packet = Packet.request(command, message)
+ self.transport.send(packet)
+ exited = False
+ while True:
+ response = Packet.parse(self.transport.receive())
+ if response.response_type == Packet.EVENT:
+ if not exited:
+ try:
+ yield Message.deserialize(response.payload)
+ except GeneratorExit:
+ exited = True
+ pass
+ else:
+ break
+
+ if response.response_type == Packet.CMD_RESPONSE:
+ command_response = Message.deserialize(response.payload)
+ else:
+ raise SessionException(
+ "Unexpected response type {type}, "
+ "expected '{response}' (CMD_RESPONSE)".format(
+ type=response.response_type,
+ response=Packet.CMD_RESPONSE
+ )
+ )
+
+ # unsubscribe from event stream
+ packet = Packet.unregister_event(event_stream_type)
+ response = self._communicate(packet)
+ if response.response_type != Packet.EVENT_CONFIRM:
+ raise SessionException(
+ "Unexpected response type {type}, "
+ "expected '{confirm}' (EVENT_CONFIRM)".format(
+ type=response.response_type,
+ confirm=Packet.EVENT_CONFIRM,
+ )
+ )
+
+ # evaluate command result, if any
+ if "success" in command_response:
+ if command_response["success"] != b"yes":
+ raise CommandException(
+ "Command failed: {errmsg}".format(
+ errmsg=command_response["errmsg"]
+ )
+ )
diff --git a/src/libcharon/plugins/vici/python/vici/test/__init__.py b/src/libcharon/plugins/vici/python/vici/test/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/vici/test/__init__.py
diff --git a/src/libcharon/plugins/vici/python/vici/test/test_protocol.py b/src/libcharon/plugins/vici/python/vici/test/test_protocol.py
new file mode 100644
index 000000000..a1f202d79
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/vici/test/test_protocol.py
@@ -0,0 +1,144 @@
+import pytest
+
+from ..protocol import Packet, Message, FiniteStream
+from ..exception import DeserializationException
+
+
+class TestPacket(object):
+ # test data definitions for outgoing packet types
+ cmd_request = b"\x00\x0c" b"command_type"
+ cmd_request_msg = b"\x00\x07" b"command" b"payload"
+ event_register = b"\x03\x0a" b"event_type"
+ event_unregister = b"\x04\x0a" b"event_type"
+
+ # test data definitions for incoming packet types
+ cmd_response = b"\x01" b"reply"
+ cmd_unknown = b"\x02"
+ event_confirm = b"\x05"
+ event_unknown = b"\x06"
+ event = b"\x07\x03" b"log" b"message"
+
+ def test_request(self):
+ assert Packet.request("command_type") == self.cmd_request
+ assert Packet.request("command", b"payload") == self.cmd_request_msg
+
+ def test_register_event(self):
+ assert Packet.register_event("event_type") == self.event_register
+
+ def test_unregister_event(self):
+ assert Packet.unregister_event("event_type") == self.event_unregister
+
+ def test_parse(self):
+ parsed_cmd_response = Packet.parse(self.cmd_response)
+ assert parsed_cmd_response.response_type == Packet.CMD_RESPONSE
+ assert parsed_cmd_response.payload.getvalue() == self.cmd_response
+
+ parsed_cmd_unknown = Packet.parse(self.cmd_unknown)
+ assert parsed_cmd_unknown.response_type == Packet.CMD_UNKNOWN
+ assert parsed_cmd_unknown.payload.getvalue() == self.cmd_unknown
+
+ parsed_event_confirm = Packet.parse(self.event_confirm)
+ assert parsed_event_confirm.response_type == Packet.EVENT_CONFIRM
+ assert parsed_event_confirm.payload.getvalue() == self.event_confirm
+
+ parsed_event_unknown = Packet.parse(self.event_unknown)
+ assert parsed_event_unknown.response_type == Packet.EVENT_UNKNOWN
+ assert parsed_event_unknown.payload.getvalue() == self.event_unknown
+
+ parsed_event = Packet.parse(self.event)
+ assert parsed_event.response_type == Packet.EVENT
+ assert parsed_event.payload.getvalue() == self.event
+
+
+class TestMessage(object):
+ """Message (de)serialization test."""
+
+ # data definitions for test of de(serialization)
+ # serialized messages holding a section
+ ser_sec_unclosed = b"\x01\x08unclosed"
+ ser_sec_single = b"\x01\x07section\x02"
+ ser_sec_nested = b"\x01\x05outer\x01\x0asubsection\x02\x02"
+
+ # serialized messages holding a list
+ ser_list_invalid = b"\x04\x07invalid\x05\x00\x02e1\x02\x03sec\x06"
+ ser_list_0_item = b"\x04\x05empty\x06"
+ ser_list_1_item = b"\x04\x01l\x05\x00\x02e1\x06"
+ ser_list_2_item = b"\x04\x01l\x05\x00\x02e1\x05\x00\x02e2\x06"
+
+ # serialized messages with key value pairs
+ ser_kv_pair = b"\x03\x03key\x00\x05value"
+ ser_kv_zero = b"\x03\x0azerolength\x00\x00"
+
+ # deserialized messages holding a section
+ des_sec_single = { "section": {} }
+ des_sec_nested = { "outer": { "subsection": {} } }
+
+ # deserialized messages holding a list
+ des_list_0_item = { "empty": [] }
+ des_list_1_item = { "l": [ b"e1" ] }
+ des_list_2_item = { "l": [ b"e1", b"e2" ] }
+
+ # deserialized messages with key value pairs
+ des_kv_pair = { "key": b"value" }
+ des_kv_zero = { "zerolength": b"" }
+
+ def test_section_serialization(self):
+ assert Message.serialize(self.des_sec_single) == self.ser_sec_single
+ assert Message.serialize(self.des_sec_nested) == self.ser_sec_nested
+
+ def test_list_serialization(self):
+ assert Message.serialize(self.des_list_0_item) == self.ser_list_0_item
+ assert Message.serialize(self.des_list_1_item) == self.ser_list_1_item
+ assert Message.serialize(self.des_list_2_item) == self.ser_list_2_item
+
+ def test_key_serialization(self):
+ assert Message.serialize(self.des_kv_pair) == self.ser_kv_pair
+ assert Message.serialize(self.des_kv_zero) == self.ser_kv_zero
+
+ def test_section_deserialization(self):
+ single = Message.deserialize(FiniteStream(self.ser_sec_single))
+ nested = Message.deserialize(FiniteStream(self.ser_sec_nested))
+
+ assert single == self.des_sec_single
+ assert nested == self.des_sec_nested
+
+ with pytest.raises(DeserializationException):
+ Message.deserialize(FiniteStream(self.ser_sec_unclosed))
+
+ def test_list_deserialization(self):
+ l0 = Message.deserialize(FiniteStream(self.ser_list_0_item))
+ l1 = Message.deserialize(FiniteStream(self.ser_list_1_item))
+ l2 = Message.deserialize(FiniteStream(self.ser_list_2_item))
+
+ assert l0 == self.des_list_0_item
+ assert l1 == self.des_list_1_item
+ assert l2 == self.des_list_2_item
+
+ with pytest.raises(DeserializationException):
+ Message.deserialize(FiniteStream(self.ser_list_invalid))
+
+ def test_key_deserialization(self):
+ pair = Message.deserialize(FiniteStream(self.ser_kv_pair))
+ zerolength = Message.deserialize(FiniteStream(self.ser_kv_zero))
+
+ assert pair == self.des_kv_pair
+ assert zerolength == self.des_kv_zero
+
+ def test_roundtrip(self):
+ message = {
+ "key1": "value1",
+ "section1": {
+ "sub-section": {
+ "key2": b"value2",
+ },
+ "list1": [ "item1", "item2" ],
+ },
+ }
+ serialized_message = FiniteStream(Message.serialize(message))
+ deserialized_message = Message.deserialize(serialized_message)
+
+ # ensure that list items and key values remain as undecoded bytes
+ deserialized_section = deserialized_message["section1"]
+ assert deserialized_message["key1"] == b"value1"
+ assert deserialized_section["sub-section"]["key2"] == b"value2"
+ assert deserialized_section["list1"] == [ b"item1", b"item2" ]
diff --git a/src/libcharon/plugins/vici/ruby/Makefile.am b/src/libcharon/plugins/vici/ruby/Makefile.am
index ce38e1c3d..3e12f86cc 100644
--- a/src/libcharon/plugins/vici/ruby/Makefile.am
+++ b/src/libcharon/plugins/vici/ruby/Makefile.am
@@ -5,8 +5,10 @@ vici.gemspec: $(srcdir)/vici.gemspec.in
-e "s:@GEM_VERSION@:$(PACKAGE_VERSION):" \
$(srcdir)/vici.gemspec.in > $@
-vici-$(PACKAGE_VERSION).gem: vici.gemspec
- $(GEM) build vici.gemspec
+vici-$(PACKAGE_VERSION).gem: vici.gemspec $(EXTRA_DIST)
+ (cd $(srcdir); $(GEM) build $(abs_builddir)/vici.gemspec)
+ [ "$(srcdir)" = "$(builddir)" ] || \
+ mv $(srcdir)/vici-$(PACKAGE_VERSION).gem $(builddir)
all-local: vici-$(PACKAGE_VERSION).gem
diff --git a/src/libcharon/plugins/vici/ruby/Makefile.in b/src/libcharon/plugins/vici/ruby/Makefile.in
index c8a8c11fb..f37c09ea2 100644
--- a/src/libcharon/plugins/vici/ruby/Makefile.in
+++ b/src/libcharon/plugins/vici/ruby/Makefile.in
@@ -142,6 +142,7 @@ DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
+EASY_INSTALL = @EASY_INSTALL@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
@@ -202,10 +203,12 @@ 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@
@@ -279,6 +282,8 @@ 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@
@@ -535,8 +540,10 @@ vici.gemspec: $(srcdir)/vici.gemspec.in
-e "s:@GEM_VERSION@:$(PACKAGE_VERSION):" \
$(srcdir)/vici.gemspec.in > $@
-vici-$(PACKAGE_VERSION).gem: vici.gemspec
- $(GEM) build vici.gemspec
+vici-$(PACKAGE_VERSION).gem: vici.gemspec $(EXTRA_DIST)
+ (cd $(srcdir); $(GEM) build $(abs_builddir)/vici.gemspec)
+ [ "$(srcdir)" = "$(builddir)" ] || \
+ mv $(srcdir)/vici-$(PACKAGE_VERSION).gem $(builddir)
all-local: vici-$(PACKAGE_VERSION).gem
diff --git a/src/libcharon/plugins/vici/ruby/lib/vici.rb b/src/libcharon/plugins/vici/ruby/lib/vici.rb
index e8a9ddca9..f87e46e69 100644
--- a/src/libcharon/plugins/vici/ruby/lib/vici.rb
+++ b/src/libcharon/plugins/vici/ruby/lib/vici.rb
@@ -243,6 +243,25 @@ module Vici
end
##
+ # Receive data from socket, until len bytes read
+ def recv_all(len)
+ encoding = ""
+ while encoding.length < len do
+ encoding << @socket.recv(len - encoding.length)
+ end
+ encoding
+ end
+
+ ##
+ # Send data to socket, until all bytes sent
+ def send_all(encoding)
+ len = 0
+ while len < encoding.length do
+ len += @socket.send(encoding[len..-1], 0)
+ end
+ end
+
+ ##
# Write a packet prefixed by its length over the transport socket. Type
# specifies the message, the optional label and message get appended.
def write(type, label, message)
@@ -253,15 +272,15 @@ module Vici
if message
encoding << message.encoding
end
- @socket.send([encoding.length + 1, type].pack("Nc") + encoding, 0)
+ send_all([encoding.length + 1, type].pack("Nc") + encoding)
end
##
# Read a packet from the transport socket. Returns the packet type, and
# if available in the packet a label and the contained message.
def read
- len = @socket.recv(4).unpack("N")[0]
- encoding = @socket.recv(len)
+ len = recv_all(4).unpack("N")[0]
+ encoding = recv_all(len)
type = encoding.unpack("c")[0]
len = 1
case type
@@ -371,7 +390,10 @@ module Vici
# during encoding.
class Connection
- def initialize(socket)
+ def initialize(socket = nil)
+ if socket == nil
+ socket = UNIXSocket.new("/var/run/charon.vici")
+ end
@transp = Transport.new(socket)
end
diff --git a/src/libcharon/plugins/vici/ruby/vici.gemspec.in b/src/libcharon/plugins/vici/ruby/vici.gemspec.in
index 5ad61c0a0..2bd2b3d88 100644
--- a/src/libcharon/plugins/vici/ruby/vici.gemspec.in
+++ b/src/libcharon/plugins/vici/ruby/vici.gemspec.in
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
s.name = "vici"
s.version = "@GEM_VERSION@"
s.authors = ["Martin Willi"]
- s.email = ["martin@strongswan.ch"]
+ s.email = ["martin@strongswan.org"]
s.description = %q{
The strongSwan VICI protocol allows external application to monitor,
configure and control the IKE daemon charon. This ruby gem provides a
diff --git a/src/libcharon/plugins/vici/vici_attribute.c b/src/libcharon/plugins/vici/vici_attribute.c
index 2178116c9..f04bae774 100644
--- a/src/libcharon/plugins/vici/vici_attribute.c
+++ b/src/libcharon/plugins/vici/vici_attribute.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2014 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
@@ -93,7 +96,8 @@ static void pool_destroy(pool_t *pool)
* Find an existing or not yet existing lease
*/
static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
- identification_t *id, host_t *requested, mem_pool_op_t op)
+ identification_t *id, host_t *requested,
+ mem_pool_op_t op, host_t *peer)
{
enumerator_t *enumerator;
host_t *addr = NULL;
@@ -106,7 +110,8 @@ static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
pool = this->pools->get(this->pools, name);
if (pool)
{
- addr = pool->vips->acquire_address(pool->vips, id, requested, op);
+ addr = pool->vips->acquire_address(pool->vips, id, requested,
+ op, peer);
if (addr)
{
break;
@@ -119,20 +124,24 @@ static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
}
METHOD(attribute_provider_t, acquire_address, host_t*,
- private_vici_attribute_t *this, linked_list_t *pools, identification_t *id,
+ private_vici_attribute_t *this, linked_list_t *pools, ike_sa_t *ike_sa,
host_t *requested)
{
- host_t *addr;
+ identification_t *id;
+ host_t *addr, *peer;
+
+ id = ike_sa->get_other_eap_id(ike_sa);
+ peer = ike_sa->get_other_host(ike_sa);
this->lock->read_lock(this->lock);
- addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING);
+ addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING, peer);
if (!addr)
{
- addr = find_addr(this, pools, id, requested, MEM_POOL_NEW);
+ addr = find_addr(this, pools, id, requested, MEM_POOL_NEW, peer);
if (!addr)
{
- addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN);
+ addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN, peer);
}
}
@@ -143,13 +152,16 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
METHOD(attribute_provider_t, release_address, bool,
private_vici_attribute_t *this, linked_list_t *pools, host_t *address,
- identification_t *id)
+ ike_sa_t *ike_sa)
{
enumerator_t *enumerator;
+ identification_t *id;
bool found = FALSE;
pool_t *pool;
char *name;
+ id = ike_sa->get_other_eap_id(ike_sa);
+
this->lock->read_lock(this->lock);
enumerator = pools->create_enumerator(pools);
@@ -256,7 +268,7 @@ static bool have_vips_from_pool(mem_pool_t *pool, linked_list_t *vips)
METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
private_vici_attribute_t *this, linked_list_t *pools,
- identification_t *id, linked_list_t *vips)
+ ike_sa_t *ike_sa, linked_list_t *vips)
{
enumerator_t *enumerator;
nested_data_t *data;
@@ -355,6 +367,24 @@ static vici_message_t* create_reply(char *fmt, ...)
}
/**
+ * Parse a range definition of an address pool
+ */
+static mem_pool_t *create_pool_range(char *name, char *buf)
+{
+ mem_pool_t *pool;
+ host_t *from, *to;
+
+ if (!host_create_from_range(buf, &from, &to))
+ {
+ return NULL;
+ }
+ pool = mem_pool_create_range(name, from, to);
+ from->destroy(from);
+ to->destroy(to);
+ return pool;
+}
+
+/**
* Parse callback data, passed to each callback
*/
typedef struct {
@@ -490,7 +520,8 @@ CALLBACK(pool_kv, bool,
if (streq(name, "addrs"))
{
char buf[128];
- host_t *base;
+ mem_pool_t *pool;
+ host_t *base = NULL;
int bits;
if (data->pool->vips)
@@ -503,14 +534,22 @@ CALLBACK(pool_kv, bool,
data->request->reply = create_reply("invalid addrs value");
return FALSE;
}
- base = host_create_from_subnet(buf, &bits);
- if (!base)
+ pool = create_pool_range(data->name, buf);
+ if (!pool)
+ {
+ base = host_create_from_subnet(buf, &bits);
+ if (base)
+ {
+ pool = mem_pool_create(data->name, base, bits);
+ base->destroy(base);
+ }
+ }
+ if (!pool)
{
data->request->reply = create_reply("invalid addrs value: %s", buf);
return FALSE;
}
- data->pool->vips = mem_pool_create(data->name, base, bits);
- base->destroy(base);
+ data->pool->vips = pool;
return TRUE;
}
data->request->reply = create_reply("invalid attribute: %s", name);
diff --git a/src/libcharon/plugins/vici/vici_builder.c b/src/libcharon/plugins/vici/vici_builder.c
index 561632049..82f12c9da 100644
--- a/src/libcharon/plugins/vici/vici_builder.c
+++ b/src/libcharon/plugins/vici/vici_builder.c
@@ -84,6 +84,8 @@ METHOD(vici_builder_t, add, void,
if (value.len > 0xffff)
{
+ DBG1(DBG_ENC, "vici value exceeds size limit (%zu > %u)",
+ value.len, 0xffff);
this->error++;
return;
}
@@ -125,24 +127,58 @@ METHOD(vici_builder_t, add, void,
}
}
-METHOD(vici_builder_t, vadd_kv, void,
- private_vici_builder_t *this, char *key, char *fmt, va_list args)
+/**
+ * Add a list item or a key/value, if key given
+ */
+static void vadd_kv_or_li(private_vici_builder_t *this, char *key,
+ char *fmt, va_list args)
{
- char buf[2048];
+ u_char buf[512];
+ chunk_t value;
ssize_t len;
+ va_list copy;
- len = vsnprintf(buf, sizeof(buf), fmt, args);
- if (len < 0 || len >= sizeof(buf))
+ va_copy(copy, args);
+ len = vsnprintf(buf, sizeof(buf), fmt, copy);
+ va_end(copy);
+ if (len >= sizeof(buf))
{
- DBG1(DBG_ENC, "vici builder format buffer exceeds limit");
+ value = chunk_alloc(len + 1);
+ len = vsnprintf(value.ptr, value.len, fmt, args);
+ }
+ else
+ {
+ value = chunk_create(buf, len);
+ }
+
+ if (len < 0)
+ {
+ DBG1(DBG_ENC, "vici builder format print failed");
this->error++;
}
else
{
- add(this, VICI_KEY_VALUE, key, chunk_create(buf, len));
+ if (key)
+ {
+ add(this, VICI_KEY_VALUE, key, value);
+ }
+ else
+ {
+ add(this, VICI_LIST_ITEM, value);
+ }
+ }
+ if (value.ptr != buf)
+ {
+ free(value.ptr);
}
}
+METHOD(vici_builder_t, vadd_kv, void,
+ private_vici_builder_t *this, char *key, char *fmt, va_list args)
+{
+ vadd_kv_or_li(this, key, fmt, args);
+}
+
METHOD(vici_builder_t, add_kv, void,
private_vici_builder_t *this, char *key, char *fmt, ...)
{
@@ -153,23 +189,10 @@ METHOD(vici_builder_t, add_kv, void,
va_end(args);
}
-
METHOD(vici_builder_t, vadd_li, void,
private_vici_builder_t *this, char *fmt, va_list args)
{
- char buf[2048];
- ssize_t len;
-
- len = vsnprintf(buf, sizeof(buf), fmt, args);
- if (len < 0 || len >= sizeof(buf))
- {
- DBG1(DBG_ENC, "vici builder format buffer exceeds limit");
- this->error++;
- }
- else
- {
- add(this, VICI_LIST_ITEM, chunk_create(buf, len));
- }
+ vadd_kv_or_li(this, NULL, fmt, args);
}
METHOD(vici_builder_t, add_li, void,
@@ -206,6 +229,13 @@ METHOD(vici_builder_t, end_list, void,
add(this, VICI_LIST_END);
}
+METHOD(vici_builder_t, destroy, void,
+ private_vici_builder_t *this)
+{
+ this->writer->destroy(this->writer);
+ free(this);
+}
+
METHOD(vici_builder_t, finalize, vici_message_t*,
private_vici_builder_t *this)
{
@@ -215,14 +245,12 @@ METHOD(vici_builder_t, finalize, vici_message_t*,
{
DBG1(DBG_ENC, "vici builder error: %u errors (section: %u, list %u)",
this->error, this->section, this->list);
- this->writer->destroy(this->writer);
- free(this);
+ destroy(this);
return NULL;
}
product = vici_message_create_from_data(
this->writer->extract_buf(this->writer), TRUE);
- this->writer->destroy(this->writer);
- free(this);
+ destroy(this);
return product;
}
@@ -245,6 +273,7 @@ vici_builder_t *vici_builder_create()
.begin_list = _begin_list,
.end_list = _end_list,
.finalize = _finalize,
+ .destroy = _destroy,
},
.writer = bio_writer_create(0),
);
diff --git a/src/libcharon/plugins/vici/vici_builder.h b/src/libcharon/plugins/vici/vici_builder.h
index 5a5cc8a03..f7d21eb8f 100644
--- a/src/libcharon/plugins/vici/vici_builder.h
+++ b/src/libcharon/plugins/vici/vici_builder.h
@@ -119,6 +119,14 @@ struct vici_builder_t {
* @return vici message, NULL on error
*/
vici_message_t* (*finalize)(vici_builder_t *this);
+
+ /**
+ * Destroy a vici builder without finalization.
+ *
+ * Note that finalize() already destroys the message, and calling destroy()
+ * is required only if the message does not get finalize()d.
+ */
+ void (*destroy)(vici_builder_t *this);
};
/**
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index 113d48084..649161020 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -1551,8 +1551,8 @@ static void clear_start_action(private_vici_config_t *this,
enumerator_t *enumerator, *children;
child_sa_t *child_sa;
ike_sa_t *ike_sa;
- u_int32_t reqid = 0, *del;
- array_t *reqids = NULL;
+ u_int32_t id = 0, *del;
+ array_t *ids = NULL;
char *name;
name = child_cfg->get_name(child_cfg);
@@ -1568,23 +1568,23 @@ static void clear_start_action(private_vici_config_t *this,
{
if (streq(name, child_sa->get_name(child_sa)))
{
- reqid = child_sa->get_reqid(child_sa);
- array_insert_create(&reqids, ARRAY_TAIL, &reqid);
+ id = child_sa->get_unique_id(child_sa);
+ array_insert_create(&ids, ARRAY_TAIL, &id);
}
}
children->destroy(children);
}
enumerator->destroy(enumerator);
- if (array_count(reqids))
+ if (array_count(ids))
{
- while (array_remove(reqids, ARRAY_HEAD, &del))
+ while (array_remove(ids, ARRAY_HEAD, &del))
{
DBG1(DBG_CFG, "closing '%s' #%u", name, *del);
charon->controller->terminate_child(charon->controller,
*del, NULL, NULL, 0);
}
- array_destroy(reqids);
+ array_destroy(ids);
}
break;
case ACTION_ROUTE:
@@ -1601,14 +1601,14 @@ static void clear_start_action(private_vici_config_t *this,
{
if (streq(name, child_sa->get_name(child_sa)))
{
- reqid = child_sa->get_reqid(child_sa);
+ id = child_sa->get_reqid(child_sa);
break;
}
}
enumerator->destroy(enumerator);
- if (reqid)
+ if (id)
{
- charon->traps->uninstall(charon->traps, reqid);
+ charon->traps->uninstall(charon->traps, id);
}
break;
}
@@ -1751,7 +1751,8 @@ CALLBACK(config_sn, bool,
.fragmentation = FRAGMENTATION_NO,
.unique = UNIQUE_NO,
.keyingtries = 1,
- .rekey_time = LFT_DEFAULT_IKE_REKEY,
+ .rekey_time = LFT_UNDEFINED,
+ .reauth_time = LFT_UNDEFINED,
.over_time = LFT_UNDEFINED,
.rand_time = LFT_UNDEFINED,
};
@@ -1809,6 +1810,20 @@ CALLBACK(config_sn, bool,
peer.local_port = charon->socket->get_port(charon->socket, FALSE);
}
+ if (peer.rekey_time == LFT_UNDEFINED && peer.reauth_time == LFT_UNDEFINED)
+ {
+ /* apply a default rekey time if no rekey/reauth time set */
+ peer.rekey_time = LFT_DEFAULT_IKE_REKEY;
+ peer.reauth_time = 0;
+ }
+ if (peer.rekey_time == LFT_UNDEFINED)
+ {
+ peer.rekey_time = 0;
+ }
+ if (peer.reauth_time == LFT_UNDEFINED)
+ {
+ peer.reauth_time = 0;
+ }
if (peer.over_time == LFT_UNDEFINED)
{
/* default over_time to 10% of rekey/reauth time if not given */
@@ -1816,9 +1831,17 @@ CALLBACK(config_sn, bool,
}
if (peer.rand_time == LFT_UNDEFINED)
{
- /* default rand_time to over_time if not given */
- peer.rand_time = min(peer.over_time,
- max(peer.rekey_time, peer.reauth_time) / 2);
+ /* default rand_time to over_time if not given, but don't make it
+ * longer than half of rekey/rauth time */
+ if (peer.rekey_time && peer.reauth_time)
+ {
+ peer.rand_time = min(peer.rekey_time, peer.reauth_time);
+ }
+ else
+ {
+ peer.rand_time = max(peer.rekey_time, peer.reauth_time);
+ }
+ peer.rand_time = min(peer.over_time, peer.rand_time / 2);
}
log_peer_data(&peer);
diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c
index 292a40032..01d503644 100644
--- a/src/libcharon/plugins/vici/vici_control.c
+++ b/src/libcharon/plugins/vici/vici_control.c
@@ -264,11 +264,11 @@ CALLBACK(terminate, vici_message_t*,
{
continue;
}
- if (child_id && child_sa->get_reqid(child_sa) != child_id)
+ if (child_id && child_sa->get_unique_id(child_sa) != child_id)
{
continue;
}
- current = child_sa->get_reqid(child_sa);
+ current = child_sa->get_unique_id(child_sa);
array_insert(ids, ARRAY_TAIL, &current);
}
csas->destroy(csas);
diff --git a/src/libcharon/plugins/vici/vici_plugin.c b/src/libcharon/plugins/vici/vici_plugin.c
index 8881feca9..af8bd283b 100644
--- a/src/libcharon/plugins/vici/vici_plugin.c
+++ b/src/libcharon/plugins/vici/vici_plugin.c
@@ -23,7 +23,6 @@
#include "vici_logger.h"
#include <library.h>
-#include <hydra.h>
#include <daemon.h>
typedef struct private_vici_plugin_t private_vici_plugin_t;
@@ -104,8 +103,8 @@ static bool register_vici(private_vici_plugin_t *this,
charon->backends->add_backend(charon->backends,
&this->config->backend);
- hydra->attributes->add_provider(hydra->attributes,
- &this->attrs->provider);
+ charon->attributes->add_provider(charon->attributes,
+ &this->attrs->provider);
charon->bus->add_logger(charon->bus, &this->logger->logger);
return TRUE;
}
@@ -114,8 +113,8 @@ static bool register_vici(private_vici_plugin_t *this,
else
{
charon->bus->remove_logger(charon->bus, &this->logger->logger);
- hydra->attributes->remove_provider(hydra->attributes,
- &this->attrs->provider);
+ charon->attributes->remove_provider(charon->attributes,
+ &this->attrs->provider);
charon->backends->remove_backend(charon->backends,
&this->config->backend);
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index 54833abde..3e0d73cdf 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -63,11 +63,13 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
enumerator_t *enumerator;
traffic_selector_t *ts;
+ b->add_kv(b, "uniqueid", "%u", child->get_unique_id(child));
b->add_kv(b, "reqid", "%u", child->get_reqid(child));
b->add_kv(b, "state", "%N", child_sa_state_names, child->get_state(child));
b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
if (child->get_state(child) == CHILD_INSTALLED ||
- child->get_state(child) == CHILD_REKEYING)
+ child->get_state(child) == CHILD_REKEYING ||
+ child->get_state(child) == CHILD_REKEYED)
{
b->add_kv(b, "protocol", "%N", protocol_id_names,
child->get_protocol(child));
@@ -507,11 +509,14 @@ static void build_auth_cfgs(peer_cfg_t *peer_cfg, bool local, vici_builder_t *b)
certificate_t *cert;
char *str;
} v;
+ char buf[32];
+ int i = 0;
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
while (enumerator->enumerate(enumerator, &auth))
{
- b->begin_section(b, local ? "local" : "remote");
+ snprintf(buf, sizeof(buf), "%s-%d", local ? "local" : "remote", ++i);
+ b->begin_section(b, buf);
rules = auth->create_enumerator(auth);
while (rules->enumerate(rules, &rule, &v))
@@ -976,10 +981,10 @@ CALLBACK(stats, vici_message_t*,
struct mallinfo mi = mallinfo();
b->begin_section(b, "mallinfo");
- b->add_kv(b, "sbrk", "%d", mi.arena);
- b->add_kv(b, "mmap", "%d", mi.hblkhd);
- b->add_kv(b, "used", "%d", mi.uordblks);
- b->add_kv(b, "free", "%d", mi.fordblks);
+ b->add_kv(b, "sbrk", "%u", mi.arena);
+ b->add_kv(b, "mmap", "%u", mi.hblkhd);
+ b->add_kv(b, "used", "%u", mi.uordblks);
+ b->add_kv(b, "free", "%u", mi.fordblks);
b->end_section(b);
}
#endif /* HAVE_MALLINFO */