summaryrefslogtreecommitdiff
path: root/src/swanctl
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2014-07-11 07:23:31 +0200
committerYves-Alexis Perez <corsac@debian.org>2014-07-11 07:23:31 +0200
commit81c63b0eed39432878f78727f60a1e7499645199 (patch)
tree82387d8fecd1c20788fd8bd784a9b0bde091fb6b /src/swanctl
parentc5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9 (diff)
downloadvyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.tar.gz
vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.zip
Imported Upstream version 5.2.0
Diffstat (limited to 'src/swanctl')
-rw-r--r--src/swanctl/Makefile.am66
-rw-r--r--src/swanctl/Makefile.in981
-rw-r--r--src/swanctl/command.c309
-rw-r--r--src/swanctl/command.h108
-rw-r--r--src/swanctl/commands/initiate.c132
-rw-r--r--src/swanctl/commands/install.c125
-rw-r--r--src/swanctl/commands/list_certs.c670
-rw-r--r--src/swanctl/commands/list_conns.c242
-rw-r--r--src/swanctl/commands/list_pols.c210
-rw-r--r--src/swanctl/commands/list_pools.c101
-rw-r--r--src/swanctl/commands/list_sas.c366
-rw-r--r--src/swanctl/commands/load_conns.c419
-rw-r--r--src/swanctl/commands/load_creds.c574
-rw-r--r--src/swanctl/commands/load_pools.c292
-rw-r--r--src/swanctl/commands/log.c101
-rw-r--r--src/swanctl/commands/stats.c118
-rw-r--r--src/swanctl/commands/terminate.c157
-rw-r--r--src/swanctl/commands/version.c96
-rw-r--r--src/swanctl/swanctl.8.in83
-rw-r--r--src/swanctl/swanctl.c57
-rw-r--r--src/swanctl/swanctl.conf306
-rw-r--r--src/swanctl/swanctl.conf.5.head.in24
-rw-r--r--src/swanctl/swanctl.conf.5.main957
-rw-r--r--src/swanctl/swanctl.conf.5.tail.in10
-rw-r--r--src/swanctl/swanctl.h69
-rw-r--r--src/swanctl/swanctl.opt779
26 files changed, 7352 insertions, 0 deletions
diff --git a/src/swanctl/Makefile.am b/src/swanctl/Makefile.am
new file mode 100644
index 000000000..385737ad4
--- /dev/null
+++ b/src/swanctl/Makefile.am
@@ -0,0 +1,66 @@
+sbin_PROGRAMS = swanctl
+
+swanctl_SOURCES = \
+ command.c command.h \
+ commands/initiate.c \
+ commands/terminate.c \
+ commands/install.c \
+ commands/list_sas.c \
+ commands/list_pols.c \
+ commands/list_conns.c \
+ commands/list_certs.c \
+ commands/list_pools.c \
+ commands/load_conns.c \
+ commands/load_creds.c \
+ commands/load_pools.c \
+ commands/log.c \
+ commands/version.c \
+ commands/stats.c \
+ swanctl.c swanctl.h
+
+swanctl_LDADD = \
+ $(top_builddir)/src/libcharon/plugins/vici/libvici.la \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la
+
+swanctl.o : $(top_builddir)/config.status
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libcharon/plugins/vici \
+ -DSWANCTLDIR=\""${swanctldir}\"" \
+ -DPLUGINS=\""${s_plugins}\""
+
+man_MANS = \
+ swanctl.8 \
+ swanctl.conf.5
+
+BUILT_SOURCES = swanctl.conf swanctl.conf.5.main
+EXTRA_DIST = swanctl.opt swanctl.conf swanctl.conf.5.main
+CLEANFILES = $(man_MANS)
+
+.opt.conf:
+ $(AM_V_GEN) \
+ $(PYTHON) $(top_srcdir)/conf/format-options.py -n -f conf $< > $(srcdir)/$@
+
+swanctl.conf.5.main: swanctl.opt
+ $(AM_V_GEN) \
+ $(PYTHON) $(top_srcdir)/conf/format-options.py -n -f man $< > $(srcdir)/$@
+
+swanctl.conf.5: swanctl.conf.5.head swanctl.conf.5.main swanctl.conf.5.tail
+ $(AM_V_GEN) \
+ cat swanctl.conf.5.head $(srcdir)/swanctl.conf.5.main swanctl.conf.5.tail > $@
+
+maintainer-clean-local:
+ cd $(srcdir) && rm -f swanctl.conf swanctl.conf.5.main
+
+install-data-local: swanctl.conf
+ test -e "$(DESTDIR)$(swanctldir)" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)"
+ test -e "$(DESTDIR)$(swanctldir)/x509" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509" || true
+ test -e "$(DESTDIR)$(swanctldir)/x509ca" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509ca" || true
+ test -e "$(DESTDIR)$(swanctldir)/x509aa" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509aa" || true
+ test -e "$(DESTDIR)$(swanctldir)/x509crl" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509crl" || true
+ test -e "$(DESTDIR)$(swanctldir)/x509ac" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509ac" || true
+ test -e "$(DESTDIR)$(swanctldir)/rsa" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/rsa" || true
+ test -e "$(DESTDIR)$(swanctldir)/ecdsa" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/ecdsa" || true
+ test -e "$(DESTDIR)$(swanctldir)/pkcs8" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/pkcs8" || true
+ test -e "$(DESTDIR)$(swanctldir)/swanctl.conf" || $(INSTALL) -m 640 $(srcdir)/swanctl.conf $(DESTDIR)$(swanctldir)/swanctl.conf || true
diff --git a/src/swanctl/Makefile.in b/src/swanctl/Makefile.in
new file mode 100644
index 000000000..149159770
--- /dev/null
+++ b/src/swanctl/Makefile.in
@@ -0,0 +1,981 @@
+# 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@
+sbin_PROGRAMS = swanctl$(EXEEXT)
+subdir = src/swanctl
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(srcdir)/swanctl.8.in $(srcdir)/swanctl.conf.5.head.in \
+ $(srcdir)/swanctl.conf.5.tail.in $(top_srcdir)/depcomp
+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 = swanctl.8 swanctl.conf.5.head swanctl.conf.5.tail
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \
+ "$(DESTDIR)$(man8dir)"
+PROGRAMS = $(sbin_PROGRAMS)
+am__dirstamp = $(am__leading_dot)dirstamp
+am_swanctl_OBJECTS = command.$(OBJEXT) commands/initiate.$(OBJEXT) \
+ commands/terminate.$(OBJEXT) commands/install.$(OBJEXT) \
+ commands/list_sas.$(OBJEXT) commands/list_pols.$(OBJEXT) \
+ commands/list_conns.$(OBJEXT) commands/list_certs.$(OBJEXT) \
+ commands/list_pools.$(OBJEXT) commands/load_conns.$(OBJEXT) \
+ commands/load_creds.$(OBJEXT) commands/load_pools.$(OBJEXT) \
+ commands/log.$(OBJEXT) commands/version.$(OBJEXT) \
+ commands/stats.$(OBJEXT) swanctl.$(OBJEXT)
+swanctl_OBJECTS = $(am_swanctl_OBJECTS)
+swanctl_DEPENDENCIES = \
+ $(top_builddir)/src/libcharon/plugins/vici/libvici.la \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+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 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(swanctl_SOURCES)
+DIST_SOURCES = $(swanctl_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(man_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+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@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+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@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RTLIB = @RTLIB@
+RUBY = @RUBY@
+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@
+libdir = @libdir@
+libexecdir = @libexecdir@
+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@
+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@
+swanctl_SOURCES = \
+ command.c command.h \
+ commands/initiate.c \
+ commands/terminate.c \
+ commands/install.c \
+ commands/list_sas.c \
+ commands/list_pols.c \
+ commands/list_conns.c \
+ commands/list_certs.c \
+ commands/list_pools.c \
+ commands/load_conns.c \
+ commands/load_creds.c \
+ commands/load_pools.c \
+ commands/log.c \
+ commands/version.c \
+ commands/stats.c \
+ swanctl.c swanctl.h
+
+swanctl_LDADD = \
+ $(top_builddir)/src/libcharon/plugins/vici/libvici.la \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libcharon/plugins/vici \
+ -DSWANCTLDIR=\""${swanctldir}\"" \
+ -DPLUGINS=\""${s_plugins}\""
+
+man_MANS = \
+ swanctl.8 \
+ swanctl.conf.5
+
+BUILT_SOURCES = swanctl.conf swanctl.conf.5.main
+EXTRA_DIST = swanctl.opt swanctl.conf swanctl.conf.5.main
+CLEANFILES = $(man_MANS)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .conf .lo .o .obj .opt
+$(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/swanctl/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/swanctl/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):
+swanctl.8: $(top_builddir)/config.status $(srcdir)/swanctl.8.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+swanctl.conf.5.head: $(top_builddir)/config.status $(srcdir)/swanctl.conf.5.head.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+swanctl.conf.5.tail: $(top_builddir)/config.status $(srcdir)/swanctl.conf.5.tail.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+commands/$(am__dirstamp):
+ @$(MKDIR_P) commands
+ @: > commands/$(am__dirstamp)
+commands/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) commands/$(DEPDIR)
+ @: > commands/$(DEPDIR)/$(am__dirstamp)
+commands/initiate.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/terminate.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/install.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/list_sas.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/list_pols.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/list_conns.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/list_certs.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/list_pools.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/load_conns.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/load_creds.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/load_pools.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/log.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/version.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+commands/stats.$(OBJEXT): commands/$(am__dirstamp) \
+ commands/$(DEPDIR)/$(am__dirstamp)
+
+swanctl$(EXEEXT): $(swanctl_OBJECTS) $(swanctl_DEPENDENCIES) $(EXTRA_swanctl_DEPENDENCIES)
+ @rm -f swanctl$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(swanctl_OBJECTS) $(swanctl_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f commands/*.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/swanctl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/initiate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/install.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/list_certs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/list_conns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/list_pols.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/list_pools.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/list_sas.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/load_conns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/load_creds.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/load_pools.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/stats.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/terminate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/version.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man5: $(man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(man_MANS)'; \
+ test -n "$(man5dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.5[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man5dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.5[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
+install-man8: $(man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(man_MANS)'; \
+ test -n "$(man8dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.8[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man8dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.8[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+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: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) 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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+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)
+ -rm -f commands/$(DEPDIR)/$(am__dirstamp)
+ -rm -f commands/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR) commands/$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man5 install-man8
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR) commands/$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic \
+ maintainer-clean-local
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-man uninstall-sbinPROGRAMS
+
+uninstall-man: uninstall-man5 uninstall-man8
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-data-local install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-man5 \
+ install-man8 install-pdf install-pdf-am install-ps \
+ install-ps-am install-sbinPROGRAMS install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic maintainer-clean-local mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-man uninstall-man5 uninstall-man8 \
+ uninstall-sbinPROGRAMS
+
+
+swanctl.o : $(top_builddir)/config.status
+
+.opt.conf:
+ $(AM_V_GEN) \
+ $(PYTHON) $(top_srcdir)/conf/format-options.py -n -f conf $< > $(srcdir)/$@
+
+swanctl.conf.5.main: swanctl.opt
+ $(AM_V_GEN) \
+ $(PYTHON) $(top_srcdir)/conf/format-options.py -n -f man $< > $(srcdir)/$@
+
+swanctl.conf.5: swanctl.conf.5.head swanctl.conf.5.main swanctl.conf.5.tail
+ $(AM_V_GEN) \
+ cat swanctl.conf.5.head $(srcdir)/swanctl.conf.5.main swanctl.conf.5.tail > $@
+
+maintainer-clean-local:
+ cd $(srcdir) && rm -f swanctl.conf swanctl.conf.5.main
+
+install-data-local: swanctl.conf
+ test -e "$(DESTDIR)$(swanctldir)" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)"
+ test -e "$(DESTDIR)$(swanctldir)/x509" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509" || true
+ test -e "$(DESTDIR)$(swanctldir)/x509ca" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509ca" || true
+ test -e "$(DESTDIR)$(swanctldir)/x509aa" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509aa" || true
+ test -e "$(DESTDIR)$(swanctldir)/x509crl" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509crl" || true
+ test -e "$(DESTDIR)$(swanctldir)/x509ac" || $(INSTALL) -d "$(DESTDIR)$(swanctldir)/x509ac" || true
+ test -e "$(DESTDIR)$(swanctldir)/rsa" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/rsa" || true
+ test -e "$(DESTDIR)$(swanctldir)/ecdsa" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/ecdsa" || true
+ test -e "$(DESTDIR)$(swanctldir)/pkcs8" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/pkcs8" || true
+ test -e "$(DESTDIR)$(swanctldir)/swanctl.conf" || $(INSTALL) -m 640 $(srcdir)/swanctl.conf $(DESTDIR)$(swanctldir)/swanctl.conf || true
+
+# 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/swanctl/command.c b/src/swanctl/command.c
new file mode 100644
index 000000000..e488273bf
--- /dev/null
+++ b/src/swanctl/command.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * 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 "command.h"
+
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <library.h>
+#include <utils/debug.h>
+#include <utils/optionsfrom.h>
+
+/**
+ * Registered commands.
+ */
+static command_t cmds[MAX_COMMANDS];
+
+/**
+ * active command.
+ */
+static int active = 0;
+
+/**
+ * number of registered commands
+ */
+static int registered = 0;
+
+/**
+ * help command index
+ */
+static int help_idx;
+
+/**
+ * Uri to connect to
+ */
+static char *uri = NULL;
+
+static int argc;
+
+static char **argv;
+
+static options_t *options;
+
+/**
+ * Global options used by all subcommands
+ */
+static struct option command_opts[MAX_COMMANDS > MAX_OPTIONS ?
+ MAX_COMMANDS : MAX_OPTIONS];
+
+/**
+ * Global optstring used by all subcommands
+ */
+static char command_optstring[(MAX_COMMANDS > MAX_OPTIONS ?
+ MAX_COMMANDS : MAX_OPTIONS) * 3];
+
+/**
+ * Build command_opts/command_optstr for the active command
+ */
+static void build_opts()
+{
+ int i, pos = 0;
+
+ memset(command_opts, 0, sizeof(command_opts));
+ memset(command_optstring, 0, sizeof(command_optstring));
+ if (active == help_idx)
+ {
+ for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
+ {
+ command_opts[i].name = cmds[i].cmd;
+ command_opts[i].val = cmds[i].op;
+ command_optstring[i] = cmds[i].op;
+ }
+ }
+ else
+ {
+ for (i = 0; cmds[active].options[i].name; i++)
+ {
+ command_opts[i].name = cmds[active].options[i].name;
+ command_opts[i].has_arg = cmds[active].options[i].arg;
+ command_opts[i].val = cmds[active].options[i].op;
+ command_optstring[pos++] = cmds[active].options[i].op;
+ switch (cmds[active].options[i].arg)
+ {
+ case optional_argument:
+ command_optstring[pos++] = ':';
+ /* FALL */
+ case required_argument:
+ command_optstring[pos++] = ':';
+ /* FALL */
+ case no_argument:
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * getopt_long wrapper
+ */
+int command_getopt(char **arg)
+{
+ int op;
+
+ while (TRUE)
+ {
+ op = getopt_long(argc, argv, command_optstring, command_opts, NULL);
+ switch (op)
+ {
+ case '+':
+ if (!options->from(options, optarg, &argc, &argv, optind))
+ {
+ /* a error value */
+ return 255;
+ }
+ continue;
+ case 'v':
+ dbg_default_set_level(atoi(optarg));
+ continue;
+ case 'u':
+ uri = optarg;
+ continue;
+ default:
+ *arg = optarg;
+ return op;
+ }
+ }
+}
+
+/**
+ * Register a command
+ */
+void command_register(command_t command)
+{
+ int i;
+
+ if (registered == MAX_COMMANDS)
+ {
+ fprintf(stderr, "unable to register command, please increase "
+ "MAX_COMMANDS\n");
+ return;
+ }
+
+ cmds[registered] = command;
+ /* append default options, but not to --help */
+ if (!active)
+ {
+ for (i = 0; i < countof(cmds[registered].options) - 1; i++)
+ {
+ if (!cmds[registered].options[i].name)
+ {
+ break;
+ }
+ }
+ if (i > countof(cmds[registered].options) - 3)
+ {
+ fprintf(stderr, "command '%s' registered too many options, please "
+ "increase MAX_OPTIONS\n", command.cmd);
+ }
+ else
+ {
+ cmds[registered].options[i++] = (command_option_t) {
+ "debug", 'v', 1, "set debug level, default: 1"
+ };
+ cmds[registered].options[i++] = (command_option_t) {
+ "options", '+', 1, "read command line options from file"
+ };
+ cmds[registered].options[i++] = (command_option_t) {
+ "uri", 'u', 1, "service URI to connect to"
+ };
+ }
+ }
+ registered++;
+}
+
+/**
+ * Print usage text, with an optional error
+ */
+int command_usage(char *error, ...)
+{
+ va_list args;
+ FILE *out = stdout;
+ int i;
+
+ if (error)
+ {
+ out = stderr;
+ fprintf(out, "Error: ");
+ va_start(args, error);
+ vfprintf(out, error, args);
+ va_end(args);
+ fprintf(out, "\n");
+ }
+ fprintf(out, "strongSwan %s swanctl\n", VERSION);
+
+ if (active == help_idx)
+ {
+ fprintf(out, "loaded plugins: %s\n",
+ lib->plugins->loaded_plugins(lib->plugins));
+ }
+
+ fprintf(out, "usage:\n");
+ if (active == help_idx)
+ {
+ for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
+ {
+ fprintf(out, " swanctl --%-10s (-%c) %s\n",
+ cmds[i].cmd, cmds[i].op, cmds[i].description);
+ }
+ }
+ else
+ {
+ for (i = 0; cmds[active].line[i]; i++)
+ {
+ if (i == 0)
+ {
+ fprintf(out, " swanctl --%s %s\n",
+ cmds[active].cmd, cmds[active].line[i]);
+ }
+ else
+ {
+ fprintf(out, " %s\n", cmds[active].line[i]);
+ }
+ }
+ for (i = 0; cmds[active].options[i].name; i++)
+ {
+ fprintf(out, " --%-15s (-%c) %s\n",
+ cmds[active].options[i].name, cmds[active].options[i].op,
+ cmds[active].options[i].desc);
+ }
+ }
+ return error != NULL;
+}
+
+/**
+ * Dispatch cleanup hook
+ */
+static void cleanup()
+{
+ options->destroy(options);
+}
+
+/**
+ * Open vici connection, call a command
+ */
+static int call_command(command_t *cmd)
+{
+ vici_conn_t *conn;
+ int ret;
+
+ conn = vici_connect(uri);
+ if (!conn)
+ {
+ command_usage("connecting to '%s' URI failed: %s",
+ uri ?: "default", strerror(errno));
+ return errno;
+ }
+ ret = cmd->call(conn);
+ vici_disconnect(conn);
+ return ret;
+}
+
+/**
+ * Dispatch commands.
+ */
+int command_dispatch(int c, char *v[])
+{
+ int op, i;
+
+ options = options_create();
+ atexit(cleanup);
+ active = help_idx = registered;
+ argc = c;
+ argv = v;
+ command_register((command_t){NULL, 'h', "help", "show usage information"});
+
+ build_opts();
+ op = getopt_long(c, v, command_optstring, command_opts, NULL);
+ for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
+ {
+ if (cmds[i].op == op)
+ {
+ active = i;
+ build_opts();
+ if (help_idx == i)
+ {
+ return command_usage(NULL);
+ }
+ return call_command(&cmds[i]);
+ }
+ }
+ return command_usage(c > 1 ? "invalid operation" : NULL);
+}
diff --git a/src/swanctl/command.h b/src/swanctl/command.h
new file mode 100644
index 000000000..8510fa44d
--- /dev/null
+++ b/src/swanctl/command.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * 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 command command
+ * @{ @ingroup swanctl
+ */
+
+#ifndef COMMAND_H_
+#define COMMAND_H_
+
+#include <libvici.h>
+#include <library.h>
+
+/**
+ * Maximum number of commands (+1).
+ */
+#define MAX_COMMANDS 16
+
+/**
+ * Maximum number of options in a command (+3)
+ */
+#define MAX_OPTIONS 32
+
+/**
+ * Maximum number of usage summary lines (+1)
+ */
+#define MAX_LINES 10
+
+typedef struct command_t command_t;
+typedef struct command_option_t command_option_t;
+typedef enum command_format_options_t command_format_options_t;
+
+/**
+ * Option specification
+ */
+struct command_option_t {
+ /** long option string of the option */
+ char *name;
+ /** short option character of the option */
+ char op;
+ /** expected argument to option, no/req/opt_argument */
+ int arg;
+ /** description of the option */
+ char *desc;
+};
+
+/**
+ * Command specification.
+ */
+struct command_t {
+ /** Function implementing the command */
+ int (*call)(vici_conn_t *conn);
+ /** short option character */
+ char op;
+ /** long option string */
+ char *cmd;
+ /** description of the command */
+ char *description;
+ /** usage summary of the command */
+ char *line[MAX_LINES];
+ /** list of options the command accepts */
+ command_option_t options[MAX_OPTIONS];
+};
+
+/**
+ * Command format options
+*/
+enum command_format_options_t {
+ COMMAND_FORMAT_NONE = 0,
+ COMMAND_FORMAT_RAW = (1<<0),
+ COMMAND_FORMAT_PRETTY = (1<<1),
+ COMMAND_FORMAT_PEM = (1<<2),
+};
+
+/**
+ * Get the next option, as with getopt.
+ */
+int command_getopt(char **arg);
+
+/**
+ * Register a command.
+ */
+void command_register(command_t command);
+
+/**
+ * Dispatch commands.
+ */
+int command_dispatch(int argc, char *argv[]);
+
+/**
+ * Show usage information of active command.
+ */
+int command_usage(char *error, ...);
+
+#endif /** COMMAND_H_ @}*/
diff --git a/src/swanctl/commands/initiate.c b/src/swanctl/commands/initiate.c
new file mode 100644
index 000000000..080dc4131
--- /dev/null
+++ b/src/swanctl/commands/initiate.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+#include <errno.h>
+
+CALLBACK(log_cb, void,
+ command_format_options_t *format, char *name, vici_res_t *msg)
+{
+ if (*format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(msg, "log", *format & COMMAND_FORMAT_PRETTY, stdout);
+ }
+ else
+ {
+ printf("[%s] %s\n",
+ vici_find_str(msg, " ", "group"),
+ vici_find_str(msg, "", "msg"));
+ }
+}
+
+static int initiate(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg, *child = NULL;
+ int ret = 0, timeout = 0, level = 1;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case 'c':
+ child = arg;
+ continue;
+ case 't':
+ timeout = atoi(arg);
+ continue;
+ case 'l':
+ level = atoi(arg);
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --initiate option");
+ }
+ break;
+ }
+
+ if (vici_register(conn, "control-log", log_cb, &format) != 0)
+ {
+ fprintf(stderr, "registering for log failed: %s\n", strerror(errno));
+ return errno;
+ }
+ req = vici_begin("initiate");
+ if (child)
+ {
+ vici_add_key_valuef(req, "child", "%s", child);
+ }
+ if (timeout)
+ {
+ vici_add_key_valuef(req, "timeout", "%d", timeout * 1000);
+ }
+ vici_add_key_valuef(req, "loglevel", "%d", level);
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "initiate request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "initiate reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else
+ {
+ if (streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ printf("initiate completed successfully\n");
+ }
+ else
+ {
+ fprintf(stderr, "initiate failed: %s\n",
+ vici_find_str(res, "", "errmsg"));
+ ret = 1;
+ }
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ initiate, 'i', "initiate", "initiate a connection",
+ {"--child <name> [--timeout <s>] [--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"child", 'c', 1, "initate a CHILD_SA configuration"},
+ {"timeout", 't', 1, "timeout in seconds before detaching"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ {"loglevel", 'l', 1, "verbosity of redirected log"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/install.c b/src/swanctl/commands/install.c
new file mode 100644
index 000000000..e8727d573
--- /dev/null
+++ b/src/swanctl/commands/install.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+#include <errno.h>
+
+static int manage_policy(vici_conn_t *conn, char *label)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg, *child = NULL;
+ int ret = 0;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_RAW;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_PRETTY;
+ continue;
+ case 'c':
+ child = arg;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --%s option", label);
+ }
+ break;
+ }
+ req = vici_begin(label);
+ if (child)
+ {
+ vici_add_key_valuef(req, "child", "%s", child);
+ }
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "%s request failed: %s\n", label, strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ puts(label);
+ vici_dump(res, " reply", format & COMMAND_FORMAT_PRETTY, stdout);
+ }
+ else
+ {
+ if (streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ printf("%s completed successfully\n", label);
+ }
+ else
+ {
+ fprintf(stderr, "%s failed: %s\n",
+ label, vici_find_str(res, "", "errmsg"));
+ ret = 1;
+ }
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+static int uninstall(vici_conn_t *conn)
+{
+ return manage_policy(conn, "uninstall");
+}
+
+static int install(vici_conn_t *conn)
+{
+ return manage_policy(conn, "install");
+}
+
+/**
+ * Register the uninstall command.
+ */
+static void __attribute__ ((constructor))reg_uninstall()
+{
+ command_register((command_t) {
+ uninstall, 'u', "uninstall", "uninstall a trap or shunt policy",
+ {"--child <name> [--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"child", 'c', 1, "CHILD_SA configuration to uninstall"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
+
+/**
+ * Register install the command.
+ */
+static void __attribute__ ((constructor))reg_install()
+{
+ command_register((command_t) {
+ install, 'p', "install", "install a trap or shunt policy",
+ {"--child <name> [--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"child", 'c', 1, "CHILD_SA configuration to install"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/list_certs.c b/src/swanctl/commands/list_certs.c
new file mode 100644
index 000000000..bee5fda27
--- /dev/null
+++ b/src/swanctl/commands/list_certs.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+#include <credentials/certificates/certificate.h>
+#include <credentials/certificates/x509.h>
+#include <credentials/certificates/crl.h>
+#include <credentials/certificates/ac.h>
+#include <selectors/traffic_selector.h>
+
+#include "command.h"
+
+/**
+ * Print PEM encoding of a certificate
+ */
+static void print_pem(certificate_t *cert)
+{
+ chunk_t encoding;
+
+ if (cert->get_encoding(cert, CERT_PEM, &encoding))
+ {
+ printf("%.*s", (int)encoding.len, encoding.ptr);
+ free(encoding.ptr);
+ }
+ else
+ {
+ fprintf(stderr, "PEM encoding certificate failed\n");
+ }
+}
+
+/**
+ * Print public key information
+ */
+static void print_pubkey(public_key_t *key, bool has_privkey)
+{
+ chunk_t chunk;
+
+ printf("pubkey: %N %d bits", key_type_names, key->get_type(key),
+ key->get_keysize(key));
+ if (has_privkey)
+ {
+ printf(", has private key");
+ }
+ printf("\n");
+ if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &chunk))
+ {
+ printf("keyid: %#B\n", &chunk);
+ }
+ if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &chunk))
+ {
+ printf("subjkey: %#B\n", &chunk);
+ }
+}
+
+/**
+ * Print X509 specific certificate information
+ */
+static void print_x509(x509_t *x509)
+{
+ enumerator_t *enumerator;
+ identification_t *id;
+ traffic_selector_t *block;
+ chunk_t chunk;
+ bool first;
+ char *uri;
+ int len, explicit, inhibit;
+ x509_flag_t flags;
+ x509_cdp_t *cdp;
+ x509_cert_policy_t *policy;
+ x509_policy_mapping_t *mapping;
+
+ chunk = chunk_skip_zero(x509->get_serial(x509));
+ printf("serial: %#B\n", &chunk);
+
+ first = TRUE;
+ enumerator = x509->create_subjectAltName_enumerator(x509);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ if (first)
+ {
+ printf("altNames: ");
+ first = FALSE;
+ }
+ else
+ {
+ printf(", ");
+ }
+ printf("%Y", id);
+ }
+ if (!first)
+ {
+ printf("\n");
+ }
+ enumerator->destroy(enumerator);
+
+ flags = x509->get_flags(x509);
+ printf("flags: ");
+ if (flags & X509_CA)
+ {
+ printf("CA ");
+ }
+ if (flags & X509_CRL_SIGN)
+ {
+ printf("CRLSign ");
+ }
+ if (flags & X509_AA)
+ {
+ printf("AA ");
+ }
+ if (flags & X509_OCSP_SIGNER)
+ {
+ printf("OCSP ");
+ }
+ if (flags & X509_AA)
+ {
+ printf("AA ");
+ }
+ if (flags & X509_SERVER_AUTH)
+ {
+ printf("serverAuth ");
+ }
+ if (flags & X509_CLIENT_AUTH)
+ {
+ printf("clientAuth ");
+ }
+ if (flags & X509_IKE_INTERMEDIATE)
+ {
+ printf("iKEIntermediate ");
+ }
+ if (flags & X509_SELF_SIGNED)
+ {
+ printf("self-signed ");
+ }
+ printf("\n");
+
+ first = TRUE;
+ enumerator = x509->create_crl_uri_enumerator(x509);
+ while (enumerator->enumerate(enumerator, &cdp))
+ {
+ if (first)
+ {
+ printf("CRL URIs: %s", cdp->uri);
+ first = FALSE;
+ }
+ else
+ {
+ printf(" %s", cdp->uri);
+ }
+ if (cdp->issuer)
+ {
+ printf(" (CRL issuer: %Y)", cdp->issuer);
+ }
+ printf("\n");
+ }
+ enumerator->destroy(enumerator);
+
+ first = TRUE;
+ enumerator = x509->create_ocsp_uri_enumerator(x509);
+ while (enumerator->enumerate(enumerator, &uri))
+ {
+ if (first)
+ {
+ printf("OCSP URIs: %s\n", uri);
+ first = FALSE;
+ }
+ else
+ {
+ printf(" %s\n", uri);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ len = x509->get_constraint(x509, X509_PATH_LEN);
+ if (len != X509_NO_CONSTRAINT)
+ {
+ printf("pathlen: %d\n", len);
+ }
+
+ first = TRUE;
+ enumerator = x509->create_name_constraint_enumerator(x509, TRUE);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ if (first)
+ {
+ printf("Permitted NameConstraints:\n");
+ first = FALSE;
+ }
+ printf(" %Y\n", id);
+ }
+ enumerator->destroy(enumerator);
+ first = TRUE;
+ enumerator = x509->create_name_constraint_enumerator(x509, FALSE);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ if (first)
+ {
+ printf("Excluded NameConstraints:\n");
+ first = FALSE;
+ }
+ printf(" %Y\n", id);
+ }
+ enumerator->destroy(enumerator);
+
+ first = TRUE;
+ enumerator = x509->create_cert_policy_enumerator(x509);
+ while (enumerator->enumerate(enumerator, &policy))
+ {
+ char *oid;
+
+ if (first)
+ {
+ printf("CertificatePolicies:\n");
+ first = FALSE;
+ }
+ oid = asn1_oid_to_string(policy->oid);
+ if (oid)
+ {
+ printf(" %s\n", oid);
+ free(oid);
+ }
+ else
+ {
+ printf(" %#B\n", &policy->oid);
+ }
+ if (policy->cps_uri)
+ {
+ printf(" CPS: %s\n", policy->cps_uri);
+ }
+ if (policy->unotice_text)
+ {
+ printf(" Notice: %s\n", policy->unotice_text);
+
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ first = TRUE;
+ enumerator = x509->create_policy_mapping_enumerator(x509);
+ while (enumerator->enumerate(enumerator, &mapping))
+ {
+ char *issuer_oid, *subject_oid;
+
+ if (first)
+ {
+ printf("PolicyMappings:\n");
+ first = FALSE;
+ }
+ issuer_oid = asn1_oid_to_string(mapping->issuer);
+ subject_oid = asn1_oid_to_string(mapping->subject);
+ printf(" %s => %s\n", issuer_oid, subject_oid);
+ free(issuer_oid);
+ free(subject_oid);
+ }
+ enumerator->destroy(enumerator);
+
+ explicit = x509->get_constraint(x509, X509_REQUIRE_EXPLICIT_POLICY);
+ inhibit = x509->get_constraint(x509, X509_INHIBIT_POLICY_MAPPING);
+ len = x509->get_constraint(x509, X509_INHIBIT_ANY_POLICY);
+
+ if (explicit != X509_NO_CONSTRAINT || inhibit != X509_NO_CONSTRAINT ||
+ len != X509_NO_CONSTRAINT)
+ {
+ printf("PolicyConstraints:\n");
+ if (explicit != X509_NO_CONSTRAINT)
+ {
+ printf(" requireExplicitPolicy: %d\n", explicit);
+ }
+ if (inhibit != X509_NO_CONSTRAINT)
+ {
+ printf(" inhibitPolicyMapping: %d\n", inhibit);
+ }
+ if (len != X509_NO_CONSTRAINT)
+ {
+ printf(" inhibitAnyPolicy: %d\n", len);
+ }
+ }
+
+ chunk = x509->get_authKeyIdentifier(x509);
+ if (chunk.ptr)
+ {
+ printf("authkeyId: %#B\n", &chunk);
+ }
+
+ chunk = x509->get_subjectKeyIdentifier(x509);
+ if (chunk.ptr)
+ {
+ printf("subjkeyId: %#B\n", &chunk);
+ }
+ if (x509->get_flags(x509) & X509_IP_ADDR_BLOCKS)
+ {
+ first = TRUE;
+ printf("addresses: ");
+ enumerator = x509->create_ipAddrBlock_enumerator(x509);
+ while (enumerator->enumerate(enumerator, &block))
+ {
+ if (first)
+ {
+ first = FALSE;
+ }
+ else
+ {
+ printf(", ");
+ }
+ printf("%R", block);
+ }
+ enumerator->destroy(enumerator);
+ printf("\n");
+ }
+}
+
+/**
+ * Print CRL specific information
+ */
+static void print_crl(crl_t *crl)
+{
+ enumerator_t *enumerator;
+ time_t ts;
+ crl_reason_t reason;
+ chunk_t chunk;
+ int count = 0;
+ bool first;
+ char buf[64];
+ struct tm tm;
+ x509_cdp_t *cdp;
+
+ chunk = chunk_skip_zero(crl->get_serial(crl));
+ printf("serial: %#B\n", &chunk);
+
+ if (crl->is_delta_crl(crl, &chunk))
+ {
+ chunk = chunk_skip_zero(chunk);
+ printf("delta CRL: for serial %#B\n", &chunk);
+ }
+ chunk = crl->get_authKeyIdentifier(crl);
+ printf("authKeyId: %#B\n", &chunk);
+
+ first = TRUE;
+ enumerator = crl->create_delta_crl_uri_enumerator(crl);
+ while (enumerator->enumerate(enumerator, &cdp))
+ {
+ if (first)
+ {
+ printf("freshest: %s", cdp->uri);
+ first = FALSE;
+ }
+ else
+ {
+ printf(" %s", cdp->uri);
+ }
+ if (cdp->issuer)
+ {
+ printf(" (CRL issuer: %Y)", cdp->issuer);
+ }
+ printf("\n");
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = crl->create_enumerator(crl);
+ while (enumerator->enumerate(enumerator, &chunk, &ts, &reason))
+ {
+ count++;
+ }
+ enumerator->destroy(enumerator);
+
+ printf("%d revoked certificate%s%s\n", count,
+ count == 1 ? "" : "s", count ? ":" : "");
+ enumerator = crl->create_enumerator(crl);
+ while (enumerator->enumerate(enumerator, &chunk, &ts, &reason))
+ {
+ chunk = chunk_skip_zero(chunk);
+ localtime_r(&ts, &tm);
+ strftime(buf, sizeof(buf), "%F %T", &tm);
+ printf(" %#B %N %s\n", &chunk, crl_reason_names, reason, buf);
+ count++;
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Print AC specific information
+ */
+static void print_ac(ac_t *ac)
+{
+ ac_group_type_t type;
+ identification_t *id;
+ enumerator_t *groups;
+ chunk_t chunk;
+ bool first = TRUE;
+
+ chunk = chunk_skip_zero(ac->get_serial(ac));
+ printf("serial: %#B\n", &chunk);
+
+ id = ac->get_holderIssuer(ac);
+ if (id)
+ {
+ printf("hissuer: \"%Y\"\n", id);
+ }
+ chunk = chunk_skip_zero(ac->get_holderSerial(ac));
+ if (chunk.ptr)
+ {
+ printf("hserial: %#B\n", &chunk);
+ }
+ groups = ac->create_group_enumerator(ac);
+ while (groups->enumerate(groups, &type, &chunk))
+ {
+ int oid;
+ char *str;
+
+ if (first)
+ {
+ printf("groups: ");
+ first = FALSE;
+ }
+ else
+ {
+ printf(" ");
+ }
+ switch (type)
+ {
+ case AC_GROUP_TYPE_STRING:
+ printf("%.*s", (int)chunk.len, chunk.ptr);
+ break;
+ case AC_GROUP_TYPE_OID:
+ oid = asn1_known_oid(chunk);
+ if (oid == OID_UNKNOWN)
+ {
+ str = asn1_oid_to_string(chunk);
+ if (str)
+ {
+ printf("%s", str);
+ free(str);
+ }
+ else
+ {
+ printf("OID:%#B", &chunk);
+ }
+ }
+ else
+ {
+ printf("%s", oid_names[oid].name);
+ }
+ break;
+ case AC_GROUP_TYPE_OCTETS:
+ printf("%#B", &chunk);
+ break;
+ }
+ printf("\n");
+ }
+ groups->destroy(groups);
+
+ chunk = ac->get_authKeyIdentifier(ac);
+ if (chunk.ptr)
+ {
+ printf("authkey: %#B\n", &chunk);
+ }
+}
+
+/**
+ * Print certificate information
+ */
+static void print_cert(certificate_t *cert, bool has_privkey)
+{
+ time_t now, notAfter, notBefore;
+ public_key_t *key;
+
+ now = time(NULL);
+
+ printf("cert: %N\n", certificate_type_names, cert->get_type(cert));
+ if (cert->get_type(cert) != CERT_X509_CRL)
+ {
+ printf("subject: \"%Y\"\n", cert->get_subject(cert));
+ }
+ printf("issuer: \"%Y\"\n", cert->get_issuer(cert));
+
+ cert->get_validity(cert, &now, &notBefore, &notAfter);
+ printf("validity: not before %T, ", &notBefore, FALSE);
+ if (now < notBefore)
+ {
+ printf("not valid yet (valid in %V)\n", &now, &notBefore);
+ }
+ else
+ {
+ printf("ok\n");
+ }
+ printf(" not after %T, ", &notAfter, FALSE);
+ if (now > notAfter)
+ {
+ printf("expired (%V ago)\n", &now, &notAfter);
+ }
+ else
+ {
+ printf("ok (expires in %V)\n", &now, &notAfter);
+ }
+
+ switch (cert->get_type(cert))
+ {
+ case CERT_X509:
+ print_x509((x509_t*)cert);
+ break;
+ case CERT_X509_CRL:
+ print_crl((crl_t*)cert);
+ break;
+ case CERT_X509_AC:
+ print_ac((ac_t*)cert);
+ break;
+ default:
+ fprintf(stderr, "parsing certificate subtype %N not implemented\n",
+ certificate_type_names, cert->get_type(cert));
+ break;
+ }
+ key = cert->get_public_key(cert);
+ if (key)
+ {
+ print_pubkey(key, has_privkey);
+ key->destroy(key);
+ }
+ printf("\n");
+}
+
+CALLBACK(list_cb, void,
+ command_format_options_t *format, char *name, vici_res_t *res)
+{
+ if (*format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "list-cert event", *format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else
+ {
+ certificate_type_t type;
+ certificate_t *cert;
+ void *buf;
+ int len;
+ bool has_privkey;
+
+ buf = vici_find(res, &len, "data");
+ has_privkey = streq(vici_find_str(res, "no", "has_privkey"), "yes");
+ if (enum_from_name(certificate_type_names,
+ vici_find_str(res, "ANY", "type"), &type) &&
+ type != CERT_ANY && buf)
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, type,
+ BUILD_BLOB_ASN1_DER, chunk_create(buf, len),
+ BUILD_END);
+ if (cert)
+ {
+ if (*format & COMMAND_FORMAT_PEM)
+ {
+ print_pem(cert);
+ }
+ else
+ {
+ print_cert(cert, has_privkey);
+ }
+ cert->destroy(cert);
+ }
+ else
+ {
+ fprintf(stderr, "parsing certificate failed\n");
+ }
+ }
+ else
+ {
+ fprintf(stderr, "received incomplete certificate data\n");
+ }
+ }
+}
+
+static int list_certs(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg, *subject = NULL, *type = NULL;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 's':
+ subject = arg;
+ continue;
+ case 't':
+ type = arg;
+ continue;
+ case 'p':
+ format |= COMMAND_FORMAT_PEM;
+ continue;
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --list-certs option");
+ }
+ break;
+ }
+ if (vici_register(conn, "list-cert", list_cb, &format) != 0)
+ {
+ fprintf(stderr, "registering for certificates failed: %s\n",
+ strerror(errno));
+ return errno;
+ }
+ req = vici_begin("list-certs");
+ if (type)
+ {
+ vici_add_key_valuef(req, "type", "%s", type);
+ }
+ if (subject)
+ {
+ vici_add_key_valuef(req, "subject", "%s", subject);
+ }
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "list-certs request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "list-certs reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ vici_free_res(res);
+ return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ list_certs, 'x', "list-certs", "list stored certificates",
+ {"[--subject <dn/san>] [--type X509|X509_AC|X509_CRL] [--pem] "
+ "[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"subject", 's', 1, "filter by certificate subject"},
+ {"type", 't', 1, "filter by certificate type"},
+ {"pem", 'p', 0, "print PEM encoding of certificate"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/list_conns.c b/src/swanctl/commands/list_conns.c
new file mode 100644
index 000000000..ec5da4bef
--- /dev/null
+++ b/src/swanctl/commands/list_conns.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+
+#include "command.h"
+
+#include <collections/hashtable.h>
+
+/**
+ * Free hashtable with contained strings
+ */
+static void free_hashtable(hashtable_t *hashtable)
+{
+ enumerator_t *enumerator;
+ char *str;
+
+ enumerator = hashtable->create_enumerator(hashtable);
+ while (enumerator->enumerate(enumerator, NULL, &str))
+ {
+ free(str);
+ }
+ enumerator->destroy(enumerator);
+
+ hashtable->destroy(hashtable);
+}
+
+CALLBACK(values, int,
+ hashtable_t *sa, vici_res_t *res, char *name, void *value, int len)
+{
+ chunk_t chunk;
+ char *str;
+
+ chunk = chunk_create(value, len);
+ if (chunk_printable(chunk, NULL, ' '))
+ {
+ if (asprintf(&str, "%.*s", len, value) >= 0)
+ {
+ free(sa->put(sa, name, str));
+ }
+ }
+ return 0;
+}
+
+
+CALLBACK(list, int,
+ hashtable_t *sa, vici_res_t *res, char *name, void *value, int len)
+{
+ chunk_t chunk;
+ char *str;
+
+ chunk = chunk_create(value, len);
+ if (chunk_printable(chunk, NULL, ' '))
+ {
+ str = sa->get(sa, name);
+ if (asprintf(&str, "%s%s%.*s",
+ str ?: "", str ? " " : "", len, value) >= 0)
+ {
+ free(sa->put(sa, name, str));
+ }
+ }
+ return 0;
+}
+
+CALLBACK(children_sn, int,
+ hashtable_t *ike, vici_res_t *res, char *name)
+{
+ hashtable_t *child;
+ int ret;
+
+ child = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1);
+ ret = vici_parse_cb(res, NULL, values, list, child);
+ if (ret == 0)
+ {
+ printf(" %s: %s\n", name, child->get(child, "mode"));
+ printf(" local: %s\n", child->get(child, "local-ts"));
+ printf(" remote: %s\n", child->get(child, "remote-ts"));
+ }
+ free_hashtable(child);
+ return ret;
+}
+
+CALLBACK(conn_sn, int,
+ hashtable_t *ike, vici_res_t *res, char *name)
+{
+ int ret = 0;
+
+ if (streq(name, "children"))
+ {
+ return vici_parse_cb(res, children_sn, NULL, NULL, NULL);
+ }
+ if (streq(name, "local") || streq(name, "remote"))
+ {
+ hashtable_t *auth;
+
+ auth = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1);
+ ret = vici_parse_cb(res, NULL, values, list, auth);
+ if (ret == 0)
+ {
+ printf(" %s %s authentication:\n",
+ name, auth->get(auth, "class") ?: "unspecified");
+ if (auth->get(auth, "id"))
+ {
+ printf(" id: %s\n", auth->get(auth, "id"));
+ }
+ if (auth->get(auth, "groups"))
+ {
+ printf(" groups: %s\n", auth->get(auth, "groups"));
+ }
+ if (auth->get(auth, "certs"))
+ {
+ printf(" certs: %s\n", auth->get(auth, "certs"));
+ }
+ if (auth->get(auth, "cacerts"))
+ {
+ printf(" cacerts: %s\n", auth->get(auth, "cacerts"));
+ }
+ }
+ free_hashtable(auth);
+ }
+ return ret;
+}
+
+CALLBACK(conn_list, int,
+ hashtable_t *sa, vici_res_t *res, char *name, void *value, int len)
+{
+ if (chunk_printable(chunk_create(value, len), NULL, ' '))
+ {
+ if (streq(name, "local_addrs"))
+ {
+ printf(" local: %.*s\n", len, value);
+ }
+ if (streq(name, "remote_addrs"))
+ {
+ printf(" remote: %.*s\n", len, value);
+ }
+ }
+ return 0;
+}
+
+CALLBACK(conns, int,
+ void *null, vici_res_t *res, char *name)
+{
+ printf("%s: %s\n", name, vici_find_str(res, "", "%s.version", name));
+
+ return vici_parse_cb(res, conn_sn, NULL, conn_list, NULL);
+}
+
+CALLBACK(list_cb, void,
+ command_format_options_t *format, char *name, vici_res_t *res)
+{
+ if (*format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "list-conn event", *format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else
+ {
+ if (vici_parse_cb(res, conns, NULL, NULL, NULL) != 0)
+ {
+ fprintf(stderr, "parsing conn event failed: %s\n", strerror(errno));
+ }
+ }
+}
+
+static int list_conns(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --list-conns option");
+ }
+ break;
+ }
+ if (vici_register(conn, "list-conn", list_cb, &format) != 0)
+ {
+ fprintf(stderr, "registering for connections failed: %s\n",
+ strerror(errno));
+ return errno;
+ }
+ req = vici_begin("list-conns");
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "list-conns request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "list-conns reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ vici_free_res(res);
+ return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ list_conns, 'L', "list-conns", "list loaded configurations",
+ {"[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/list_pols.c b/src/swanctl/commands/list_pols.c
new file mode 100644
index 000000000..2317b2542
--- /dev/null
+++ b/src/swanctl/commands/list_pols.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+
+#include "command.h"
+
+#include <collections/hashtable.h>
+
+/**
+ * Free hashtable with contained strings
+ */
+static void free_hashtable(hashtable_t *hashtable)
+{
+ enumerator_t *enumerator;
+ char *str;
+
+ enumerator = hashtable->create_enumerator(hashtable);
+ while (enumerator->enumerate(enumerator, NULL, &str))
+ {
+ free(str);
+ }
+ enumerator->destroy(enumerator);
+
+ hashtable->destroy(hashtable);
+}
+
+CALLBACK(policy_values, int,
+ hashtable_t *pol, vici_res_t *res, char *name, void *value, int len)
+{
+ chunk_t chunk;
+ char *str;
+
+ chunk = chunk_create(value, len);
+ if (chunk_printable(chunk, NULL, ' '))
+ {
+ if (asprintf(&str, "%.*s", len, value) >= 0)
+ {
+ free(pol->put(pol, name, str));
+ }
+ }
+ return 0;
+}
+
+CALLBACK(policy_list, int,
+ hashtable_t *pol, vici_res_t *res, char *name, void *value, int len)
+{
+ chunk_t chunk;
+ char *str;
+
+ chunk = chunk_create(value, len);
+ if (chunk_printable(chunk, NULL, ' '))
+ {
+ str = pol->get(pol, name);
+ if (asprintf(&str, "%s%s%.*s",
+ str ?: "", str ? " " : "", len, value) >= 0)
+ {
+ free(pol->put(pol, name, str));
+ }
+ }
+ return 0;
+}
+
+CALLBACK(policies, int,
+ void *null, vici_res_t *res, char *name)
+{
+ hashtable_t *pol;
+ int ret;
+
+ pol = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1);
+ ret = vici_parse_cb(res, NULL, policy_values, policy_list, pol);
+
+ printf("%s, %s\n", name, pol->get(pol, "mode"));
+ printf(" local: %s\n", pol->get(pol, "local-ts"));
+ printf(" remote: %s\n", pol->get(pol, "remote-ts"));
+
+ free_hashtable(pol);
+ return ret;
+}
+
+CALLBACK(list_cb, void,
+ command_format_options_t *format, char *name, vici_res_t *res)
+{
+ if (*format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "list-policy event", *format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else
+ {
+ if (vici_parse_cb(res, policies, NULL, NULL, NULL) != 0)
+ {
+ fprintf(stderr, "parsing policy event failed: %s\n", strerror(errno));
+ }
+ }
+}
+
+static int list_pols(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ bool trap = FALSE, drop = FALSE, pass = FALSE;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg, *child = NULL;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'c':
+ child = arg;
+ continue;
+ case 't':
+ trap = TRUE;
+ continue;
+ case 'd':
+ drop = TRUE;
+ continue;
+ case 'p':
+ pass = TRUE;
+ continue;
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --list-pols option");
+ }
+ break;
+ }
+ if (!trap && !drop && !pass)
+ {
+ trap = drop = pass = TRUE;
+ }
+ if (vici_register(conn, "list-policy", list_cb, &format) != 0)
+ {
+ fprintf(stderr, "registering for policies failed: %s\n",
+ strerror(errno));
+ return errno;
+ }
+ req = vici_begin("list-policies");
+ if (child)
+ {
+ vici_add_key_valuef(req, "child", "%s", child);
+ }
+ if (trap)
+ {
+ vici_add_key_valuef(req, "trap", "yes");
+ }
+ if (drop)
+ {
+ vici_add_key_valuef(req, "drop", "yes");
+ }
+ if (pass)
+ {
+ vici_add_key_valuef(req, "pass", "yes");
+ }
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "list-policies request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "list-policies reply", format & COMMAND_FORMAT_PRETTY, stdout);
+ }
+ vici_free_res(res);
+ return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ list_pols, 'P', "list-pols", "list currently installed policies",
+ {"[--child <name>] [--trap] [--drop] [--pass] [--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"child", 'c', 1, "filter policies by CHILD_SA config name"},
+ {"trap", 't', 0, "list trap policies"},
+ {"drop", 'd', 0, "list drop policies"},
+ {"pass", 'p', 0, "list bypass policies"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/list_pools.c b/src/swanctl/commands/list_pools.c
new file mode 100644
index 000000000..17ea539a9
--- /dev/null
+++ b/src/swanctl/commands/list_pools.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+
+#include "command.h"
+
+CALLBACK(list_pool, int,
+ linked_list_t *list, vici_res_t *res, char *name)
+{
+ char pool[64], leases[32];
+
+ snprintf(pool, sizeof(pool), "%s:", name);
+ snprintf(leases, sizeof(leases), "%s / %s / %s",
+ vici_find_str(res, "", "%s.online", name),
+ vici_find_str(res, "", "%s.offline", name),
+ vici_find_str(res, "", "%s.size", name));
+
+ printf("%-20s %-30s %16s\n",
+ name, vici_find_str(res, "", "%s.base", name), leases);
+
+ return 0;
+}
+
+static int list_pools(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg;
+ int ret = 0;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --list-pools option");
+ }
+ break;
+ }
+
+ req = vici_begin("get-pools");
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "get-pools request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "get-pools reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else
+ {
+ ret = vici_parse_cb(res, list_pool, NULL, NULL, NULL);
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ list_pools, 'A', "list-pools", "list loaded pool configurations",
+ {"[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/list_sas.c b/src/swanctl/commands/list_sas.c
new file mode 100644
index 000000000..80c279ce8
--- /dev/null
+++ b/src/swanctl/commands/list_sas.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+
+#include "command.h"
+
+#include <collections/hashtable.h>
+
+/**
+ * Free hashtable with contained strings
+ */
+static void free_hashtable(hashtable_t *hashtable)
+{
+ enumerator_t *enumerator;
+ char *str;
+
+ enumerator = hashtable->create_enumerator(hashtable);
+ while (enumerator->enumerate(enumerator, NULL, &str))
+ {
+ free(str);
+ }
+ enumerator->destroy(enumerator);
+
+ hashtable->destroy(hashtable);
+}
+
+CALLBACK(sa_values, int,
+ hashtable_t *sa, vici_res_t *res, char *name, void *value, int len)
+{
+ chunk_t chunk;
+ char *str;
+
+ chunk = chunk_create(value, len);
+ if (chunk_printable(chunk, NULL, ' '))
+ {
+ if (asprintf(&str, "%.*s", len, value) >= 0)
+ {
+ free(sa->put(sa, name, str));
+ }
+ }
+ return 0;
+}
+
+
+CALLBACK(sa_list, int,
+ hashtable_t *sa, vici_res_t *res, char *name, void *value, int len)
+{
+ chunk_t chunk;
+ char *str;
+
+ chunk = chunk_create(value, len);
+ if (chunk_printable(chunk, NULL, ' '))
+ {
+ str = sa->get(sa, name);
+ if (asprintf(&str, "%s%s%.*s",
+ str ?: "", str ? " " : "", len, value) >= 0)
+ {
+ free(sa->put(sa, name, str));
+ }
+ }
+ return 0;
+}
+
+CALLBACK(child_sas, int,
+ hashtable_t *ike, vici_res_t *res, char *name)
+{
+ hashtable_t *child;
+ int ret;
+
+ child = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1);
+ ret = vici_parse_cb(res, NULL, sa_values, sa_list, child);
+ if (ret == 0)
+ {
+ printf(" %s: #%s, %s, %s%s, %s:",
+ name, child->get(child, "reqid"),
+ child->get(child, "state"), child->get(child, "mode"),
+ child->get(child, "encap") ? "-in-UDP" : "",
+ child->get(child, "protocol"));
+
+ if (child->get(child, "encr-alg"))
+ {
+ printf("%s", child->get(child, "encr-alg"));
+ if (child->get(child, "encr-keysize"))
+ {
+ printf("-%s", child->get(child, "encr-keysize"));
+ }
+ }
+ if (child->get(child, "integ-alg"))
+ {
+ if (child->get(child, "encr-alg"))
+ {
+ printf("/");
+ }
+ printf("%s", child->get(child, "integ-alg"));
+ if (child->get(child, "integ-keysize"))
+ {
+ printf("-%s", child->get(child, "integ-keysize"));
+ }
+ }
+ if (child->get(child, "prf-alg"))
+ {
+ printf("/%s", child->get(child, "prf-alg"));
+ }
+ if (child->get(child, "dh-group"))
+ {
+ printf("/%s", child->get(child, "dh-group"));
+ }
+ if (child->get(child, "esn"))
+ {
+ printf("/%s", child->get(child, "esn"));
+ }
+ printf("\n");
+
+ printf(" installed %s ago", child->get(child, "install-time"));
+ if (child->get(child, "rekey-time"))
+ {
+ printf(", rekeying in %ss", child->get(child, "rekey-time"));
+ }
+ if (child->get(child, "life-time"))
+ {
+ printf(", expires in %ss", child->get(child, "life-time"));
+ }
+ printf("\n");
+
+ printf(" in %s%s%s", child->get(child, "spi-in"),
+ child->get(child, "cpi-in") ? "/" : "",
+ child->get(child, "cpi-in") ?: "");
+ printf(", %6s bytes, %5s packets",
+ child->get(child, "bytes-in"), child->get(child, "packets-in"));
+ if (child->get(child, "use-in"))
+ {
+ printf(", %5ss ago", child->get(child, "use-in"));
+ }
+ printf("\n");
+
+ printf(" out %s%s%s", child->get(child, "spi-out"),
+ child->get(child, "cpi-out") ? "/" : "",
+ child->get(child, "cpi-out") ?: "");
+ printf(", %6s bytes, %5s packets",
+ child->get(child, "bytes-out"), child->get(child, "packets-out"));
+ if (child->get(child, "use-out"))
+ {
+ printf(", %5ss ago", child->get(child, "use-out"));
+ }
+ printf("\n");
+
+ printf(" local %s\n", child->get(child, "local-ts"));
+ printf(" remote %s\n", child->get(child, "remote-ts"));
+ }
+ free_hashtable(child);
+ return ret;
+}
+
+CALLBACK(ike_sa, int,
+ hashtable_t *ike, vici_res_t *res, char *name)
+{
+ if (streq(name, "child-sas"))
+ {
+ printf("%s: #%s, %s, IKEv%s, %s:%s\n",
+ ike->get(ike, "name"), ike->get(ike, "uniqueid"),
+ ike->get(ike, "state"), ike->get(ike, "version"),
+ ike->get(ike, "initiator-spi"), ike->get(ike, "responder-spi"));
+
+ printf(" local '%s' @ %s\n",
+ ike->get(ike, "local-id"), ike->get(ike, "local-host"));
+ printf(" remote '%s' @ %s",
+ ike->get(ike, "remote-id"), ike->get(ike, "remote-host"));
+ if (ike->get(ike, "remote-eap-id"))
+ {
+ printf(" EAP: '%s'", ike->get(ike, "remote-eap-id"));
+ }
+ if (ike->get(ike, "remote-xauth-id"))
+ {
+ printf(" XAuth: '%s'", ike->get(ike, "remote-xauth-id"));
+ }
+ printf("\n");
+
+ if (ike->get(ike, "encr-alg"))
+ {
+ printf(" %s", ike->get(ike, "encr-alg"));
+ if (ike->get(ike, "encr-keysize"))
+ {
+ printf("-%s", ike->get(ike, "encr-keysize"));
+ }
+ if (ike->get(ike, "integ-alg"))
+ {
+ printf("/%s", ike->get(ike, "integ-alg"));
+ }
+ if (ike->get(ike, "integ-keysize"))
+ {
+ printf("-%s", ike->get(ike, "integ-keysize"));
+ }
+ printf("/%s", ike->get(ike, "prf-alg"));
+ printf("/%s", ike->get(ike, "dh-group"));
+ printf("\n");
+ }
+
+ if (ike->get(ike, "established"))
+ {
+ printf(" established %ss ago", ike->get(ike, "established"));
+ if (ike->get(ike, "rekey-time"))
+ {
+ printf(", rekeying in %ss", ike->get(ike, "rekey-time"));
+ }
+ if (ike->get(ike, "reauth-time"))
+ {
+ printf(", reauth in %ss", ike->get(ike, "reauth-time"));
+ }
+ if (ike->get(ike, "life-time"))
+ {
+ printf(", expires in %ss", ike->get(ike, "life-time"));
+ }
+ printf("\n");
+ }
+
+ if (ike->get(ike, "tasks-queued"))
+ {
+ printf(" queued: %s\n", ike->get(ike, "tasks-queued"));
+ }
+ if (ike->get(ike, "tasks-active"))
+ {
+ printf(" active: %s\n", ike->get(ike, "tasks-active"));
+ }
+ if (ike->get(ike, "tasks-passive"))
+ {
+ printf(" passive: %s\n", ike->get(ike, "tasks-passive"));
+ }
+
+ return vici_parse_cb(res, child_sas, NULL, NULL, ike);
+ }
+ return 0;
+}
+
+CALLBACK(ike_sas, int,
+ void *null, vici_res_t *res, char *name)
+{
+ hashtable_t *ike;
+ int ret;
+
+ ike = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1);
+ ike->put(ike, "name", strdup(name));
+ ret = vici_parse_cb(res, ike_sa, sa_values, sa_list, ike);
+ free_hashtable(ike);
+ return ret;
+}
+
+CALLBACK(list_cb, void,
+ command_format_options_t *format, char *name, vici_res_t *res)
+{
+ if (*format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "list-sa event", *format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else
+ {
+ if (vici_parse_cb(res, ike_sas, NULL, NULL, NULL) != 0)
+ {
+ fprintf(stderr, "parsing SA event failed: %s\n", strerror(errno));
+ }
+ }
+}
+
+static int list_sas(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ bool noblock = FALSE;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg, *ike = NULL;
+ int ike_id = 0;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'i':
+ ike = arg;
+ continue;
+ case 'I':
+ ike_id = atoi(arg);
+ continue;
+ case 'n':
+ noblock = TRUE;
+ continue;
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --list-sas option");
+ }
+ break;
+ }
+ if (vici_register(conn, "list-sa", list_cb, &format) != 0)
+ {
+ fprintf(stderr, "registering for SAs failed: %s\n", strerror(errno));
+ return errno;
+ }
+ req = vici_begin("list-sas");
+ if (ike)
+ {
+ vici_add_key_valuef(req, "ike", "%s", ike);
+ }
+ if (ike_id)
+ {
+ vici_add_key_valuef(req, "ike-id", "%d", ike_id);
+ }
+ if (noblock)
+ {
+ vici_add_key_valuef(req, "noblock", "yes");
+ }
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "list-sas request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "list-sas reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ vici_free_res(res);
+ return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ list_sas, 'l', "list-sas", "list currently active IKE_SAs",
+ {"[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"ike", 'i', 1, "filter IKE_SAs by name"},
+ {"ike-id", 'I', 1, "filter IKE_SAs by unique identifier"},
+ {"noblock", 'n', 0, "don't wait for IKE_SAs in use"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/load_conns.c b/src/swanctl/commands/load_conns.c
new file mode 100644
index 000000000..7383f7a1e
--- /dev/null
+++ b/src/swanctl/commands/load_conns.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "command.h"
+#include "swanctl.h"
+
+/**
+ * Check if we should handle a key as a list of comma separated values
+ */
+static bool is_list_key(char *key)
+{
+ char *keys[] = {
+ "local_addrs",
+ "remote_addrs",
+ "proposals",
+ "esp_proposals",
+ "ah_proposals",
+ "local_ts",
+ "remote_ts",
+ "vips",
+ "pools",
+ "groups",
+ };
+ int i;
+
+ for (i = 0; i < countof(keys); i++)
+ {
+ if (strcaseeq(keys[i], key))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Check if we should handle a key as a list of comma separated files
+ */
+static bool is_file_list_key(char *key)
+{
+ char *keys[] = {
+ "certs",
+ "cacerts",
+ };
+ int i;
+
+ for (i = 0; i < countof(keys); i++)
+ {
+ if (strcaseeq(keys[i], key))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Add a vici list from a comma separated string value
+ */
+static void add_list_key(vici_req_t *req, char *key, char *value)
+{
+ enumerator_t *enumerator;
+ char *token;
+
+ vici_begin_list(req, key);
+ enumerator = enumerator_create_token(value, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ vici_add_list_itemf(req, "%s", token);
+ }
+ enumerator->destroy(enumerator);
+ vici_end_list(req);
+}
+
+/**
+ * Add a vici list of blobs from a comma separated file list
+ */
+static void add_file_list_key(vici_req_t *req, char *key, char *value)
+{
+ enumerator_t *enumerator;
+ chunk_t *map;
+ char *token, buf[PATH_MAX];
+
+ vici_begin_list(req, key);
+ enumerator = enumerator_create_token(value, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ if (!path_absolute(token))
+ {
+ if (streq(key, "certs"))
+ {
+ snprintf(buf, sizeof(buf), "%s%s%s",
+ SWANCTL_X509DIR, DIRECTORY_SEPARATOR, token);
+ token = buf;
+ }
+ if (streq(key, "cacerts"))
+ {
+ snprintf(buf, sizeof(buf), "%s%s%s",
+ SWANCTL_X509CADIR, DIRECTORY_SEPARATOR, token);
+ token = buf;
+ }
+ }
+
+ map = chunk_map(token, FALSE);
+ if (map)
+ {
+ vici_add_list_item(req, map->ptr, map->len);
+ chunk_unmap(map);
+ }
+ else
+ {
+ fprintf(stderr, "loading certificate '%s' failed: %s\n",
+ token, strerror(errno));
+ }
+ }
+ enumerator->destroy(enumerator);
+ vici_end_list(req);
+}
+
+/**
+ * Translate setting key/values from a section into vici key-values/lists
+ */
+static void add_key_values(vici_req_t *req, settings_t *cfg, char *section)
+{
+ enumerator_t *enumerator;
+ char *key, *value;
+
+ enumerator = cfg->create_key_value_enumerator(cfg, section);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ if (is_list_key(key))
+ {
+ add_list_key(req, key, value);
+ }
+ else if (is_file_list_key(key))
+ {
+ add_file_list_key(req, key, value);
+ }
+ else
+ {
+ vici_add_key_valuef(req, key, "%s", value);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Translate a settings section to a vici section
+ */
+static void add_sections(vici_req_t *req, settings_t *cfg, char *section)
+{
+ enumerator_t *enumerator;
+ char *name, buf[256];
+
+ enumerator = cfg->create_section_enumerator(cfg, section);
+ while (enumerator->enumerate(enumerator, &name))
+ {
+ vici_begin_section(req, name);
+ snprintf(buf, sizeof(buf), "%s.%s", section, name);
+ add_key_values(req, cfg, buf);
+ add_sections(req, cfg, buf);
+ vici_end_section(req);
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Load an IKE_SA config with CHILD_SA configs from a section
+ */
+static bool load_conn(vici_conn_t *conn, settings_t *cfg,
+ char *section, command_format_options_t format)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ bool ret = TRUE;
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%s.%s", "connections", section);
+
+ req = vici_begin("load-conn");
+
+ vici_begin_section(req, section);
+ add_key_values(req, cfg, buf);
+ add_sections(req, cfg, buf);
+ vici_end_section(req);
+
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "load-conn request failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "load-conn reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ fprintf(stderr, "loading connection '%s' failed: %s\n",
+ section, vici_find_str(res, "", "errmsg"));
+ ret = FALSE;
+ }
+ else
+ {
+ printf("loaded connection '%s'\n", section);
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+CALLBACK(list_conn, int,
+ linked_list_t *list, vici_res_t *res, char *name, void *value, int len)
+{
+ if (streq(name, "conns"))
+ {
+ char *str;
+
+ if (asprintf(&str, "%.*s", len, value) != -1)
+ {
+ list->insert_last(list, str);
+ }
+ }
+ return 0;
+}
+
+/**
+ * Create a list of currently loaded connections
+ */
+static linked_list_t* list_conns(vici_conn_t *conn,
+ command_format_options_t format)
+{
+ linked_list_t *list;
+ vici_res_t *res;
+
+ list = linked_list_create();
+
+ res = vici_submit(vici_begin("get-conns"), conn);
+ if (res)
+ {
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "get-conns reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ vici_parse_cb(res, NULL, NULL, list_conn, list);
+ vici_free_res(res);
+ }
+ return list;
+}
+
+/**
+ * Remove and free a string from a list
+ */
+static void remove_from_list(linked_list_t *list, char *str)
+{
+ enumerator_t *enumerator;
+ char *current;
+
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ if (streq(current, str))
+ {
+ list->remove_at(list, enumerator);
+ free(current);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Unload a connection by name
+ */
+static bool unload_conn(vici_conn_t *conn, char *name,
+ command_format_options_t format)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ bool ret = TRUE;
+
+ req = vici_begin("unload-conn");
+ vici_add_key_valuef(req, "name", "%s", name);
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "unload-conn request failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "unload-conn reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ fprintf(stderr, "unloading connection '%s' failed: %s\n",
+ name, vici_find_str(res, "", "errmsg"));
+ ret = FALSE;
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+static int load_conns(vici_conn_t *conn)
+{
+ u_int found = 0, loaded = 0, unloaded = 0;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg, *section;
+ enumerator_t *enumerator;
+ linked_list_t *conns;
+ settings_t *cfg;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --load-conns option");
+ }
+ break;
+ }
+
+ cfg = settings_create(SWANCTL_CONF);
+ if (!cfg)
+ {
+ fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
+ return EINVAL;
+ }
+
+ conns = list_conns(conn, format);
+
+ enumerator = cfg->create_section_enumerator(cfg, "connections");
+ while (enumerator->enumerate(enumerator, &section))
+ {
+ remove_from_list(conns, section);
+ found++;
+ if (load_conn(conn, cfg, section, format))
+ {
+ loaded++;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ cfg->destroy(cfg);
+
+ /* unload all connection in daemon, but not in file */
+ while (conns->remove_first(conns, (void**)&section) == SUCCESS)
+ {
+ if (unload_conn(conn, section, format))
+ {
+ unloaded++;
+ }
+ free(section);
+ }
+ conns->destroy(conns);
+
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ return 0;
+ }
+ if (found == 0)
+ {
+ printf("no connections found, %u unloaded\n", unloaded);
+ return 0;
+ }
+ if (loaded == found)
+ {
+ printf("successfully loaded %u connections, %u unloaded\n",
+ loaded, unloaded);
+ return 0;
+ }
+ fprintf(stderr, "loaded %u of %u connections, %u failed to load, "
+ "%u unloaded\n", loaded, found, found - loaded, unloaded);
+ return EINVAL;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ load_conns, 'c', "load-conns", "(re-)load connection configuration",
+ {"[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/load_creds.c b/src/swanctl/commands/load_creds.c
new file mode 100644
index 000000000..f77084c60
--- /dev/null
+++ b/src/swanctl/commands/load_creds.c
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "command.h"
+#include "swanctl.h"
+
+#include <credentials/sets/mem_cred.h>
+#include <credentials/sets/callback_cred.h>
+
+/**
+ * Load a single certificate over vici
+ */
+static bool load_cert(vici_conn_t *conn, command_format_options_t format,
+ char *dir, char *type, chunk_t data)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ bool ret = TRUE;
+
+ req = vici_begin("load-cert");
+
+ vici_add_key_valuef(req, "type", "%s", type);
+ vici_add_key_value(req, "data", data.ptr, data.len);
+
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "load-cert request failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "load-cert reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ fprintf(stderr, "loading '%s' failed: %s\n",
+ dir, vici_find_str(res, "", "errmsg"));
+ ret = FALSE;
+ }
+ else
+ {
+ printf("loaded %s certificate '%s'\n", type, dir);
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+/**
+ * Load certficiates from a directory
+ */
+static void load_certs(vici_conn_t *conn, command_format_options_t format,
+ char *type, char *dir)
+{
+ enumerator_t *enumerator;
+ struct stat st;
+ chunk_t *map;
+ char *path;
+
+ enumerator = enumerator_create_directory(dir);
+ if (enumerator)
+ {
+ while (enumerator->enumerate(enumerator, NULL, &path, &st))
+ {
+ if (S_ISREG(st.st_mode))
+ {
+ map = chunk_map(path, FALSE);
+ if (map)
+ {
+ load_cert(conn, format, path, type, *map);
+ chunk_unmap(map);
+ }
+ else
+ {
+ fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
+ path, strerror(errno));
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+}
+
+/**
+ * Load a single private key over vici
+ */
+static bool load_key(vici_conn_t *conn, command_format_options_t format,
+ char *dir, char *type, chunk_t data)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ bool ret = TRUE;
+
+ req = vici_begin("load-key");
+
+ vici_add_key_valuef(req, "type", "%s", type);
+ vici_add_key_value(req, "data", data.ptr, data.len);
+
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "load-key reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ fprintf(stderr, "loading '%s' failed: %s\n",
+ dir, vici_find_str(res, "", "errmsg"));
+ ret = FALSE;
+ }
+ else
+ {
+ printf("loaded %s key '%s'\n", type, dir);
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+/**
+ * Callback function to prompt for private key passwords
+ */
+CALLBACK(password_cb, shared_key_t*,
+ char *prompt, shared_key_type_t type,
+ identification_t *me, identification_t *other,
+ id_match_t *match_me, id_match_t *match_other)
+{
+ char *pwd = NULL;
+
+ if (type != SHARED_PRIVATE_KEY_PASS)
+ {
+ return NULL;
+ }
+#ifdef HAVE_GETPASS
+ pwd = getpass(prompt);
+#endif
+ if (!pwd || strlen(pwd) == 0)
+ {
+ return NULL;
+ }
+ if (match_me)
+ {
+ *match_me = ID_MATCH_PERFECT;
+ }
+ if (match_other)
+ {
+ *match_other = ID_MATCH_PERFECT;
+ }
+ return shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
+}
+
+/**
+ * Try to parse a potentially encrypted private key using password prompt
+ */
+static private_key_t* decrypt_key(char *name, char *type, chunk_t encoding)
+{
+ key_type_t kt = KEY_ANY;
+ private_key_t *private;
+ callback_cred_t *cb;
+ char buf[128];
+
+ if (streq(type, "rsa"))
+ {
+ kt = KEY_RSA;
+ }
+ else if (streq(type, "ecdsa"))
+ {
+ kt = KEY_ECDSA;
+ }
+
+ snprintf(buf, sizeof(buf), "Password for '%s': ", name);
+
+ cb = callback_cred_create_shared(password_cb, buf);
+ lib->credmgr->add_set(lib->credmgr, &cb->set);
+
+ private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, kt,
+ BUILD_BLOB_PEM, encoding, BUILD_END);
+
+ lib->credmgr->remove_set(lib->credmgr, &cb->set);
+ cb->destroy(cb);
+
+ return private;
+}
+
+/**
+ * Try to parse a potentially encrypted private key using configured secret
+ */
+static private_key_t* decrypt_key_with_config(settings_t *cfg, char *name,
+ char *type, chunk_t encoding)
+{ key_type_t kt = KEY_ANY;
+ enumerator_t *enumerator, *secrets;
+ char *section, *key, *value, *file, buf[128];
+ shared_key_t *shared;
+ private_key_t *private = NULL;
+ mem_cred_t *mem = NULL;
+
+ if (streq(type, "rsa"))
+ {
+ kt = KEY_RSA;
+ }
+ else if (streq(type, "ecdsa"))
+ {
+ kt = KEY_ECDSA;
+ }
+ else
+ {
+ type = "pkcs8";
+ }
+
+ /* load all secrets for this key type */
+ enumerator = cfg->create_section_enumerator(cfg, "secrets");
+ while (enumerator->enumerate(enumerator, &section))
+ {
+ if (strpfx(section, type))
+ {
+ file = cfg->get_str(cfg, "secrets.%s.file", NULL, section);
+ if (file && strcaseeq(file, name))
+ {
+ snprintf(buf, sizeof(buf), "secrets.%s", section);
+ secrets = cfg->create_key_value_enumerator(cfg, buf);
+ while (secrets->enumerate(secrets, &key, &value))
+ {
+ if (strpfx(key, "secret"))
+ {
+ if (!mem)
+ {
+ mem = mem_cred_create();
+ }
+ shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
+ chunk_clone(chunk_from_str(value)));
+ mem->add_shared(mem, shared, NULL);
+ }
+ }
+ secrets->destroy(secrets);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (mem)
+ {
+ lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
+
+ private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, kt,
+ BUILD_BLOB_PEM, encoding, BUILD_END);
+
+ lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
+
+ if (!private)
+ {
+ fprintf(stderr, "configured decryption secret for '%s' invalid\n",
+ name);
+ }
+
+ mem->destroy(mem);
+ }
+
+ return private;
+}
+
+/**
+ * Try to decrypt and load a private key
+ */
+static bool load_encrypted_key(vici_conn_t *conn,
+ command_format_options_t format, settings_t *cfg,
+ char *rel, char *path, char *type, bool noprompt,
+ chunk_t data)
+{
+ private_key_t *private;
+ bool loaded = FALSE;
+ chunk_t encoding;
+
+ private = decrypt_key_with_config(cfg, rel, type, data);
+ if (!private && !noprompt)
+ {
+ private = decrypt_key(rel, type, data);
+ }
+ if (private)
+ {
+ if (private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
+ {
+ switch (private->get_type(private))
+ {
+ case KEY_RSA:
+ loaded = load_key(conn, format, path, "rsa", encoding);
+ break;
+ case KEY_ECDSA:
+ loaded = load_key(conn, format, path, "ecdsa", encoding);
+ break;
+ default:
+ break;
+ }
+ chunk_clear(&encoding);
+ }
+ private->destroy(private);
+ }
+ return loaded;
+}
+
+/**
+ * Load private keys from a directory
+ */
+static void load_keys(vici_conn_t *conn, command_format_options_t format,
+ bool noprompt, settings_t *cfg, char *type, char *dir)
+{
+ enumerator_t *enumerator;
+ struct stat st;
+ chunk_t *map;
+ char *path, *rel;
+
+ enumerator = enumerator_create_directory(dir);
+ if (enumerator)
+ {
+ while (enumerator->enumerate(enumerator, &rel, &path, &st))
+ {
+ if (S_ISREG(st.st_mode))
+ {
+ map = chunk_map(path, FALSE);
+ if (map)
+ {
+ if (!load_encrypted_key(conn, format, cfg, rel, path, type,
+ noprompt, *map))
+ {
+ load_key(conn, format, path, type, *map);
+ }
+ chunk_unmap(map);
+ }
+ else
+ {
+ fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
+ path, strerror(errno));
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+}
+
+/**
+ * Load a single secret over VICI
+ */
+static bool load_secret(vici_conn_t *conn, settings_t *cfg,
+ char *section, command_format_options_t format)
+{
+ enumerator_t *enumerator;
+ vici_req_t *req;
+ vici_res_t *res;
+ chunk_t data;
+ char *key, *value, buf[128], *type = NULL;
+ bool ret = TRUE;
+ int i;
+ char *types[] = {
+ "eap",
+ "xauth",
+ "ike",
+ "rsa",
+ "ecdsa",
+ "pkcs8",
+ };
+
+ for (i = 0; i < countof(types); i++)
+ {
+ if (strpfx(section, types[i]))
+ {
+ type = types[i];
+ break;
+ }
+ }
+ if (!type)
+ {
+ fprintf(stderr, "ignoring unsupported secret '%s'\n", section);
+ return FALSE;
+ }
+ if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ike"))
+ { /* skip non-shared secrets */
+ return TRUE;
+ }
+
+ value = cfg->get_str(cfg, "secrets.%s.secret", NULL, section);
+ if (!value)
+ {
+ fprintf(stderr, "missing secret in '%s', ignored\n", section);
+ return FALSE;
+ }
+ if (strcasepfx(value, "0x"))
+ {
+ data = chunk_from_hex(chunk_from_str(value + 2), NULL);
+ }
+ else if (strcasepfx(value, "0s"))
+ {
+ data = chunk_from_base64(chunk_from_str(value + 2), NULL);
+ }
+ else
+ {
+ data = chunk_clone(chunk_from_str(value));
+ }
+
+ req = vici_begin("load-shared");
+
+ vici_add_key_valuef(req, "type", "%s", type);
+ vici_add_key_value(req, "data", data.ptr, data.len);
+ chunk_clear(&data);
+
+ vici_begin_list(req, "owners");
+ snprintf(buf, sizeof(buf), "secrets.%s", section);
+ enumerator = cfg->create_key_value_enumerator(cfg, buf);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ if (strpfx(key, "id"))
+ {
+ vici_add_list_itemf(req, "%s", value);
+ }
+ }
+ enumerator->destroy(enumerator);
+ vici_end_list(req);
+
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "load-shared reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ fprintf(stderr, "loading shared secret failed: %s\n",
+ vici_find_str(res, "", "errmsg"));
+ ret = FALSE;
+ }
+ else
+ {
+ printf("loaded %s secret '%s'\n", type, section);
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+/**
+ * Clear all currently loaded credentials
+ */
+static bool clear_creds(vici_conn_t *conn, command_format_options_t format)
+{
+ vici_res_t *res;
+
+ res = vici_submit(vici_begin("clear-creds"), conn);
+ if (!res)
+ {
+ fprintf(stderr, "clear-creds request failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "clear-creds reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ vici_free_res(res);
+ return TRUE;
+}
+
+static int load_creds(vici_conn_t *conn)
+{
+ bool clear = FALSE, noprompt = FALSE;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ enumerator_t *enumerator;
+ settings_t *cfg;
+ char *arg, *section;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'c':
+ clear = TRUE;
+ continue;
+ case 'n':
+ noprompt = TRUE;
+ continue;
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --load-creds option");
+ }
+ break;
+ }
+
+ if (clear)
+ {
+ if (!clear_creds(conn, format))
+ {
+ return ECONNREFUSED;
+ }
+ }
+
+ cfg = settings_create(SWANCTL_CONF);
+ if (!cfg)
+ {
+ fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
+ return EINVAL;
+ }
+
+ load_certs(conn, format, "x509", SWANCTL_X509DIR);
+ load_certs(conn, format, "x509ca", SWANCTL_X509CADIR);
+ load_certs(conn, format, "x509aa", SWANCTL_X509AADIR);
+ load_certs(conn, format, "x509crl", SWANCTL_X509CRLDIR);
+ load_certs(conn, format, "x509ac", SWANCTL_X509ACDIR);
+
+ load_keys(conn, format, noprompt, cfg, "rsa", SWANCTL_RSADIR);
+ load_keys(conn, format, noprompt, cfg, "ecdsa", SWANCTL_ECDSADIR);
+ load_keys(conn, format, noprompt, cfg, "any", SWANCTL_PKCS8DIR);
+
+ enumerator = cfg->create_section_enumerator(cfg, "secrets");
+ while (enumerator->enumerate(enumerator, &section))
+ {
+ load_secret(conn, cfg, section, format);
+ }
+ enumerator->destroy(enumerator);
+
+ cfg->destroy(cfg);
+
+ return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ load_creds, 's', "load-creds", "(re-)load credentials",
+ {"[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"clear", 'c', 0, "clear previously loaded credentials"},
+ {"noprompt", 'n', 0, "do not prompt for passwords"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/load_pools.c b/src/swanctl/commands/load_pools.c
new file mode 100644
index 000000000..0ec56cc43
--- /dev/null
+++ b/src/swanctl/commands/load_pools.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "command.h"
+#include "swanctl.h"
+
+/**
+ * Add a vici list from a comma separated string value
+ */
+static void add_list_key(vici_req_t *req, char *key, char *value)
+{
+ enumerator_t *enumerator;
+ char *token;
+
+ vici_begin_list(req, key);
+ enumerator = enumerator_create_token(value, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ vici_add_list_itemf(req, "%s", token);
+ }
+ enumerator->destroy(enumerator);
+ vici_end_list(req);
+}
+
+/**
+ * Translate setting key/values from a section into vici key-values/lists
+ */
+static void add_key_values(vici_req_t *req, settings_t *cfg, char *section)
+{
+ enumerator_t *enumerator;
+ char *key, *value;
+
+ enumerator = cfg->create_key_value_enumerator(cfg, section);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ /* pool subnet is encoded as key/value, all other attributes as list */
+ if (streq(key, "addrs"))
+ {
+ vici_add_key_valuef(req, key, "%s", value);
+ }
+ else
+ {
+ add_list_key(req, key, value);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Load a pool configuration
+ */
+static bool load_pool(vici_conn_t *conn, settings_t *cfg,
+ char *section, command_format_options_t format)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ bool ret = TRUE;
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%s.%s", "pools", section);
+
+ req = vici_begin("load-pool");
+
+ vici_begin_section(req, section);
+ add_key_values(req, cfg, buf);
+ vici_end_section(req);
+
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "load-pool request failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "load-pool reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ fprintf(stderr, "loading pool '%s' failed: %s\n",
+ section, vici_find_str(res, "", "errmsg"));
+ ret = FALSE;
+ }
+ else
+ {
+ printf("loaded pool '%s'\n", section);
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+CALLBACK(list_pool, int,
+ linked_list_t *list, vici_res_t *res, char *name)
+{
+ list->insert_last(list, strdup(name));
+ return 0;
+}
+
+/**
+ * Create a list of currently loaded pools
+ */
+static linked_list_t* list_pools(vici_conn_t *conn,
+ command_format_options_t format)
+{
+ linked_list_t *list;
+ vici_res_t *res;
+
+ list = linked_list_create();
+
+ res = vici_submit(vici_begin("get-pools"), conn);
+ if (res)
+ {
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "get-pools reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ vici_parse_cb(res, list_pool, NULL, NULL, list);
+ vici_free_res(res);
+ }
+ return list;
+}
+
+/**
+ * Remove and free a string from a list
+ */
+static void remove_from_list(linked_list_t *list, char *str)
+{
+ enumerator_t *enumerator;
+ char *current;
+
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ if (streq(current, str))
+ {
+ list->remove_at(list, enumerator);
+ free(current);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Unload a pool by name
+ */
+static bool unload_pool(vici_conn_t *conn, char *name,
+ command_format_options_t format)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ bool ret = TRUE;
+
+ req = vici_begin("unload-pool");
+ vici_add_key_valuef(req, "name", "%s", name);
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "unload-pool request failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "unload-pool reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ fprintf(stderr, "unloading pool '%s' failed: %s\n",
+ name, vici_find_str(res, "", "errmsg"));
+ ret = FALSE;
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+static int load_pools(vici_conn_t *conn)
+{
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ u_int found = 0, loaded = 0, unloaded = 0;
+ char *arg, *section;
+ enumerator_t *enumerator;
+ linked_list_t *pools;
+ settings_t *cfg;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --load-pools option");
+ }
+ break;
+ }
+
+ cfg = settings_create(SWANCTL_CONF);
+ if (!cfg)
+ {
+ fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
+ return EINVAL;
+ }
+
+ pools = list_pools(conn, format);
+
+ enumerator = cfg->create_section_enumerator(cfg, "pools");
+ while (enumerator->enumerate(enumerator, &section))
+ {
+ remove_from_list(pools, section);
+ found++;
+ if (load_pool(conn, cfg, section, format))
+ {
+ loaded++;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ cfg->destroy(cfg);
+
+ /* unload all pools in daemon, but not in file */
+ while (pools->remove_first(pools, (void**)&section) == SUCCESS)
+ {
+ if (unload_pool(conn, section, format))
+ {
+ unloaded++;
+ }
+ free(section);
+ }
+ pools->destroy(pools);
+
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ return 0;
+ }
+ if (found == 0)
+ {
+ printf("no pools found, %u unloaded\n", unloaded);
+ return 0;
+ }
+ if (loaded == found)
+ {
+ printf("successfully loaded %u pools, %u unloaded\n",
+ loaded, unloaded);
+ return 0;
+ }
+ fprintf(stderr, "loaded %u of %u pools, %u failed to load, "
+ "%u unloaded\n", loaded, found, found - loaded, unloaded);
+ return EINVAL;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ load_pools, 'a', "load-pools", "(re-)load pool configuration",
+ {"[--raw|--pretty"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/log.c b/src/swanctl/commands/log.c
new file mode 100644
index 000000000..99ba328a7
--- /dev/null
+++ b/src/swanctl/commands/log.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+CALLBACK(log_cb, void,
+ command_format_options_t *format, char *name, vici_res_t *msg)
+{
+ if (*format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(msg, "log", *format & COMMAND_FORMAT_PRETTY, stdout);
+ }
+ else
+ {
+ char *current, *next;
+
+ current = vici_find_str(msg, NULL, "msg");
+ while (current)
+ {
+ next = strchr(current, '\n');
+ printf("%.2d[%s] ", vici_find_int(msg, 0, "thread"),
+ vici_find_str(msg, " ", "group"));
+ if (next == NULL)
+ {
+ printf("%s\n", current);
+ break;
+ }
+ printf("%.*s\n", (int)(next - current), current);
+ current = next + 1;
+ }
+ }
+}
+
+static int logcmd(vici_conn_t *conn)
+{
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --log option");
+ }
+ break;
+ }
+
+ if (vici_register(conn, "log", log_cb, &format) != 0)
+ {
+ fprintf(stderr, "registering for log failed: %s\n", strerror(errno));
+ return errno;
+ }
+
+ wait_sigint();
+
+ fprintf(stderr, "disconnecting...\n");
+
+ return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ logcmd, 'T', "log", "trace logging output",
+ {"[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/stats.c b/src/swanctl/commands/stats.c
new file mode 100644
index 000000000..b5425f504
--- /dev/null
+++ b/src/swanctl/commands/stats.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+#include <errno.h>
+
+static int stats(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ char *arg;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --stats option");
+ }
+ break;
+ }
+
+ req = vici_begin("stats");
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "stats request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "stats reply", format & COMMAND_FORMAT_PRETTY, stdout);
+ }
+ else
+ {
+ printf("uptime: %s, since %s\n",
+ vici_find_str(res, "", "uptime.running"),
+ vici_find_str(res, "", "uptime.since"));
+
+ printf("worker threads: %s total, %s idle, working: %s/%s/%s/%s\n",
+ vici_find_str(res, "", "workers.total"),
+ vici_find_str(res, "", "workers.idle"),
+ vici_find_str(res, "", "workers.active.critical"),
+ vici_find_str(res, "", "workers.active.high"),
+ vici_find_str(res, "", "workers.active.medium"),
+ vici_find_str(res, "", "workers.active.low"));
+
+ printf("job queues: %s/%s/%s/%s\n",
+ vici_find_str(res, "", "queues.critical"),
+ vici_find_str(res, "", "queues.high"),
+ vici_find_str(res, "", "queues.medium"),
+ vici_find_str(res, "", "queues.low"));
+
+ printf("jobs scheduled: %s\n",
+ vici_find_str(res, "", "scheduled"));
+
+ printf("IKE_SAs: %s total, %s half-open\n",
+ vici_find_str(res, "", "ikesas.total"),
+ vici_find_str(res, "", "ikesas.half-open"));
+
+ if (vici_find_str(res, NULL, "mem.total"))
+ {
+ printf("memory usage: %s bytes, %s allocations\n",
+ vici_find_str(res, "", "mem.total"),
+ vici_find_str(res, "", "mem.allocs"));
+ }
+ if (vici_find_str(res, NULL, "mallinfo.sbrk"))
+ {
+ printf("mallinfo: sbrk %s, mmap %s, used %s, free %s\n",
+ vici_find_str(res, "", "mallinfo.sbrk"),
+ vici_find_str(res, "", "mallinfo.mmap"),
+ vici_find_str(res, "", "mallinfo.used"),
+ vici_find_str(res, "", "mallinfo.free"));
+ }
+ }
+ vici_free_res(res);
+ return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ stats, 'S', "stats", "show daemon stats information",
+ {"[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/terminate.c b/src/swanctl/commands/terminate.c
new file mode 100644
index 000000000..689ba4d50
--- /dev/null
+++ b/src/swanctl/commands/terminate.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+#include <errno.h>
+
+CALLBACK(log_cb, void,
+ command_format_options_t *format, char *name, vici_res_t *msg)
+{
+ if (*format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(msg, "log", *format & COMMAND_FORMAT_PRETTY, stdout);
+ }
+ else
+ {
+ printf("[%s] %s\n",
+ vici_find_str(msg, " ", "group"),
+ vici_find_str(msg, "", "msg"));
+ }
+}
+
+static int terminate(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+ char *arg, *child = NULL, *ike = NULL;
+ int ret = 0, timeout = 0, level = 1, child_id = 0, ike_id = 0;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case 'c':
+ child = arg;
+ continue;
+ case 'i':
+ ike = arg;
+ continue;
+ case 'C':
+ child_id = atoi(arg);
+ continue;
+ case 'I':
+ ike_id = atoi(arg);
+ continue;
+ case 't':
+ timeout = atoi(arg);
+ continue;
+ case 'l':
+ level = atoi(arg);
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --terminate option");
+ }
+ break;
+ }
+
+ if (vici_register(conn, "control-log", log_cb, &format) != 0)
+ {
+ fprintf(stderr, "registering for log failed: %s\n", strerror(errno));
+ return errno;
+ }
+ req = vici_begin("terminate");
+ if (child)
+ {
+ vici_add_key_valuef(req, "child", "%s", child);
+ }
+ if (ike)
+ {
+ vici_add_key_valuef(req, "ike", "%s", ike);
+ }
+ if (child_id)
+ {
+ vici_add_key_valuef(req, "child-id", "%d", child_id);
+ }
+ if (ike_id)
+ {
+ vici_add_key_valuef(req, "ike-id", "%d", ike_id);
+ }
+ if (timeout)
+ {
+ vici_add_key_valuef(req, "timeout", "%d", timeout * 1000);
+ }
+ vici_add_key_valuef(req, "loglevel", "%d", level);
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "terminate request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "terminate reply", format & COMMAND_FORMAT_PRETTY,
+ stdout);
+ }
+ else
+ {
+ if (streq(vici_find_str(res, "no", "success"), "yes"))
+ {
+ printf("terminate completed successfully\n");
+ }
+ else
+ {
+ fprintf(stderr, "terminate failed: %s\n",
+ vici_find_str(res, "", "errmsg"));
+ ret = 1;
+ }
+ }
+ vici_free_res(res);
+ return ret;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ terminate, 't', "terminate", "terminate a connection",
+ {"--child <name> | --ike <name | --child-id <id> | --ike-id <id>",
+ "[--timeout <s>] [--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"child", 'c', 1, "terminate by CHILD_SA name"},
+ {"ike", 'i', 1, "terminate by IKE_SA name"},
+ {"child-id", 'C', 1, "terminate by CHILD_SA reqid"},
+ {"ike-id", 'I', 1, "terminate by IKE_SA unique identifier"},
+ {"timeout", 't', 1, "timeout in seconds before detaching"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ {"loglevel", 'l', 1, "verbosity of redirected log"},
+ }
+ });
+}
diff --git a/src/swanctl/commands/version.c b/src/swanctl/commands/version.c
new file mode 100644
index 000000000..4f24a0fc2
--- /dev/null
+++ b/src/swanctl/commands/version.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+#include <errno.h>
+
+static int version(vici_conn_t *conn)
+{
+ vici_req_t *req;
+ vici_res_t *res;
+ char *arg;
+ bool daemon = FALSE;
+ command_format_options_t format = COMMAND_FORMAT_NONE;
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ return command_usage(NULL);
+ case 'P':
+ format |= COMMAND_FORMAT_PRETTY;
+ /* fall through to raw */
+ case 'r':
+ format |= COMMAND_FORMAT_RAW;
+ continue;
+ case 'd':
+ daemon = TRUE;
+ continue;
+ case EOF:
+ break;
+ default:
+ return command_usage("invalid --terminate option");
+ }
+ break;
+ }
+
+ if (!daemon)
+ {
+ printf("strongSwan swanctl %s\n", VERSION);
+ return 0;
+ }
+
+ req = vici_begin("version");
+ res = vici_submit(req, conn);
+ if (!res)
+ {
+ fprintf(stderr, "version request failed: %s\n", strerror(errno));
+ return errno;
+ }
+ if (format & COMMAND_FORMAT_RAW)
+ {
+ vici_dump(res, "version reply", format & COMMAND_FORMAT_PRETTY, stdout);
+ }
+ else
+ {
+ printf("strongSwan %s %s (%s, %s, %s)\n",
+ vici_find_str(res, "", "version"),
+ vici_find_str(res, "", "daemon"),
+ vici_find_str(res, "", "sysname"),
+ vici_find_str(res, "", "release"),
+ vici_find_str(res, "", "machine"));
+ }
+ vici_free_res(res);
+ return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ version, 'v', "version", "show version information",
+ {"[--raw|--pretty]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"daemon", 'd', 0, "query daemon version"},
+ {"raw", 'r', 0, "dump raw response message"},
+ {"pretty", 'P', 0, "dump raw response message in pretty print"},
+ }
+ });
+}
diff --git a/src/swanctl/swanctl.8.in b/src/swanctl/swanctl.8.in
new file mode 100644
index 000000000..d7abae67a
--- /dev/null
+++ b/src/swanctl/swanctl.8.in
@@ -0,0 +1,83 @@
+.TH SWANCTL 8 "2014-04-28" "@PACKAGE_VERSION@" "strongSwan"
+.SH NAME
+swanctl \- strongSwan configuration, control and monitoring command line interface.
+.SH SYNOPSIS
+.SY "swanctl"
+.I command
+.RI [ option\~ .\|.\|.]
+.YS
+.
+.SY "swanctl"
+.B \-h
+|
+.B \-\-help
+.YS
+.
+.SH DESCRIPTION
+swanctl is a cross-platform command line utility to configure, control and
+monitor the strongSwan IKE daemon. It is a replacement for the aging
+.BR starter ,
+.B ipsec
+and
+.B stroke
+tools.
+
+swanctl uses a configuration file called
+.BR swanctl.conf (5)
+to parse configurations and credentials. Private keys, certificates and other
+PKI related credentials are read from specific directories.
+
+To communicate with the IKE daemon, swanctl uses the VICI protocol, the
+Versatile IKE Configuration Interface. This stable interface is usable by
+other tools and is often preferable than scripting swanctl and parsing its
+output.
+
+.SH COMMANDS
+.TP
+.B "\-i, \-\-initiate"
+initiate a connection
+.TP
+.B "\-t, \-\-terminate"
+\-\-terminate\fR
+terminate a connection
+.TP
+.B "\-p, \-\-install"
+install a trap or shunt policy
+.TP
+.B "\-u, \-\-uninstall"
+uninstall a trap or shunt policy
+.TP
+.B "\-l, \-\-list\-sas"
+list currently active IKE_SAs
+.TP
+.B "\-P, \-\-list\-pols"
+list currently installed policies
+.TP
+.B "\-L, \-\-list\-conns"
+list loaded configurations
+.TP
+.B "\-x, \-\-list\-certs"
+list stored certificates
+.TP
+.B "\-A, \-\-list\-pools"
+list loaded pool configurations
+.TP
+.B "\-c, \-\-load\-conns"
+(re\-)load connection configuration
+.TP
+.B "\-s, \-\-load\-creds"
+(re\-)load credentials
+.TP
+.B "\-a, \-\-load\-pools"
+(re\-)load pool configuration
+.TP
+.B "\-T, \-\-log"
+trace logging output
+.TP
+.B "\-v, \-\-version"
+show daemon version information
+.TP
+.B "\-h, \-\-help"
+show usage information
+.SH SEE ALSO
+.BR swanctl.conf (5)
diff --git a/src/swanctl/swanctl.c b/src/swanctl/swanctl.c
new file mode 100644
index 000000000..dc5af79a7
--- /dev/null
+++ b/src/swanctl/swanctl.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "command.h"
+
+#include <unistd.h>
+
+#include <library.h>
+
+/**
+ * Cleanup library atexit()
+ */
+static void cleanup()
+{
+ lib->processor->cancel(lib->processor);
+ library_deinit();
+}
+
+/**
+ * Library initialization and operation parsing
+ */
+int main(int argc, char *argv[])
+{
+ atexit(cleanup);
+ if (!library_init(NULL, "swanctl"))
+ {
+ exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
+ }
+ if (lib->integrity &&
+ !lib->integrity->check_file(lib->integrity, "swanctl", argv[0]))
+ {
+ fprintf(stderr, "integrity check of swanctl failed\n");
+ exit(SS_RC_DAEMON_INTEGRITY);
+ }
+ if (!lib->plugins->load(lib->plugins,
+ lib->settings->get_str(lib->settings, "swanctl.load", PLUGINS)))
+ {
+ exit(SS_RC_INITIALIZATION_FAILED);
+ }
+ dbg_default_set_level(0);
+ lib->processor->set_threads(lib->processor, 4);
+ dbg_default_set_level(1);
+
+ return command_dispatch(argc, argv);
+}
diff --git a/src/swanctl/swanctl.conf b/src/swanctl/swanctl.conf
new file mode 100644
index 000000000..8cff81feb
--- /dev/null
+++ b/src/swanctl/swanctl.conf
@@ -0,0 +1,306 @@
+# Section defining IKE connection configurations.
+# connections {
+
+ # Section for an IKE connection named <conn>.
+ # <conn> {
+
+ # IKE major version to use for connection.
+ # version = 0
+
+ # Local address(es) to use for IKE communication, comma separated.
+ # local_addrs = %any
+
+ # Remote address(es) to use for IKE communication, comma separated.
+ # remote_addrs = %any
+
+ # Local UPD port for IKE communication.
+ # local_port = 500
+
+ # Remote UDP port for IKE communication.
+ # remote_port = 500
+
+ # Comma separated proposals to accept for IKE.
+ # proposals = default
+
+ # Virtual IPs to request in configuration payload / Mode Config.
+ # vips =
+
+ # Use Aggressive Mode in IKEv1.
+ # aggressive = no
+
+ # Set the Mode Config mode to use.
+ # pull = yes
+
+ # Enforce UDP encapsulation by faking NAT-D payloads.
+ # encap = no
+
+ # Enables MOBIKE on IKEv2 connections.
+ # mobike = yes
+
+ # Interval of liveness checks (DPD).
+ # dpd_delay = 0s
+
+ # Timeout for DPD checks (IKEV1 only).
+ # dpd_timeout = 0s
+
+ # Use IKEv1 UDP packet fragmentation (yes, no or force).
+ # fragmentation = no
+
+ # Send certificate requests payloads (yes or no).
+ # send_certreq = yes
+
+ # Send certificate payloads (yes, no or ifasked).
+ # send_cert = ifasked
+
+ # Number of retransmission sequences to perform during initial connect.
+ # keyingtries = 1
+
+ # Connection uniqueness policy (never, no, keep or replace).
+ # unique = no
+
+ # Time to schedule IKE reauthentication.
+ # reauth_time = 0s
+
+ # Time to schedule IKE rekeying.
+ # rekey_time = 4h
+
+ # Hard IKE_SA lifetime if rekey/reauth does not complete, as time.
+ # over_time = 10% of rekey_time/reauth_time
+
+ # Range of random time to subtract from rekey/reauth times.
+ # rand_time = over_time
+
+ # Comma separated list of named IP pools.
+ # pools =
+
+ # Section for a local authentication round.
+ # local<suffix> {
+
+ # Comma separated list of certificate candidates to use for
+ # authentication.
+ # certs =
+
+ # Authentication to perform locally (pubkey, psk, xauth[-backend] or
+ # eap[-method]).
+ # auth = pubkey
+
+ # IKE identity to use for authentication round.
+ # id =
+
+ # Client EAP-Identity to use in EAP-Identity exchange and the EAP
+ # method.
+ # eap_id = id
+
+ # Server side EAP-Identity to expect in the EAP method.
+ # aaa_id = remote-id
+
+ # Client XAuth username used in the XAuth exchange.
+ # xauth_id = id
+
+ # }
+
+ # Section for a remote authentication round.
+ # remote<suffix> {
+
+ # IKE identity to expect for authentication round.
+ # id = %any
+
+ # Authorization group memberships to require.
+ # groups =
+
+ # Comma separated list of certificate to accept for authentication.
+ # certs =
+
+ # Comma separated list of CA certificates to accept for
+ # authentication.
+ # cacert =
+
+ # Certificate revocation policy, (strict, ifuri or relaxed).
+ # revocation = relaxed
+
+ # Authentication to expect from remote (pubkey, psk, xauth[-backend]
+ # or eap[-method]).
+ # auth = pubkey
+
+ # }
+
+ # children {
+
+ # CHILD_SA configuration sub-section.
+ # <child> {
+
+ # AH proposals to offer for the CHILD_SA.
+ # ah_proposals =
+
+ # ESP proposals to offer for the CHILD_SA.
+ # esp_proposals = default
+
+ # Local traffic selectors to include in CHILD_SA.
+ # local_ts = dynamic
+
+ # Remote selectors to include in CHILD_SA.
+ # remote_ts = dynamic
+
+ # Time to schedule CHILD_SA rekeying.
+ # rekey_time = 1h
+
+ # Maximum lifetime before CHILD_SA gets closed, as time.
+ # life_time = rekey_time + 10%
+
+ # Range of random time to subtract from rekey_time.
+ # rand_time = life_time - rekey_time
+
+ # Number of bytes processed before initiating CHILD_SA rekeying.
+ # rekey_bytes = 0
+
+ # Maximum bytes processed before CHILD_SA gets closed.
+ # life_bytes = rekey_bytes + 10%
+
+ # Range of random bytes to subtract from rekey_bytes.
+ # rand_bytes = life_bytes - rekey_bytes
+
+ # Number of packets processed before initiating CHILD_SA
+ # rekeying.
+ # rekey_packets = 0
+
+ # Maximum number of packets processed before CHILD_SA gets
+ # closed.
+ # life_packets = rekey_packets + 10%
+
+ # Range of random packets to subtract from packets_bytes.
+ # rand_packets = life_packets - rekey_packets
+
+ # Updown script to invoke on CHILD_SA up and down events.
+ # updown =
+
+ # Hostaccess variable to pass to updown script.
+ # hostaccess = yes
+
+ # IPsec Mode to establish (tunnel, transport, beet, pass or
+ # drop).
+ # mode = tunnel
+
+ # Action to perform on DPD timeout (clear, trap or restart).
+ # dpd_action = clear
+
+ # Enable IPComp compression before encryption.
+ # ipcomp = no
+
+ # Timeout before closing CHILD_SA after inactivity.
+ # inactivity = 0s
+
+ # Fixed reqid to use for this CHILD_SA.
+ # reqid = 0
+
+ # Netfilter mark and mask for input traffic.
+ # mark_in = 0/0x00000000
+
+ # Netfilter mark and mask for output traffic.
+ # mark_out = 0/0x00000000
+
+ # Traffic Flow Confidentiality padding.
+ # tfc_padding = 0
+
+ # IPsec replay window to configure for this CHILD_SA.
+ # replay_window = 32
+
+ # Action to perform after loading the configuration (none, trap,
+ # start).
+ # start_action = none
+
+ # Action to perform after a CHILD_SA gets closed (none, trap,
+ # start).
+ # close_action = none
+
+ # }
+
+ # }
+
+ # }
+
+# }
+
+# Section defining secrets for IKE/EAP/XAuth authentication and private key
+# decryption.
+# secrets {
+
+ # EAP secret section for a specific secret.
+ # eap<suffix> {
+
+ # Value of the EAP/XAuth secret.
+ # secret =
+
+ # Identity the EAP/XAuth secret belongs to.
+ # id<suffix> =
+
+ # }
+
+ # XAuth secret section for a specific secret.
+ # xauth<suffix> {
+
+ # }
+
+ # IKE preshared secret section for a specific secret.
+ # ike<suffix> {
+
+ # Value of the IKE preshared secret.
+ # secret =
+
+ # IKE identity the IKE preshared secret belongs to.
+ # id<suffix> =
+
+ # }
+
+ # Private key decryption passphrase for a key in the rsa folder.
+ # rsa<suffix> {
+
+ # File name in the rsa folder for which this passphrase should be used.
+ # file =
+
+ # Value of decryption passphrase for RSA key.
+ # secret =
+
+ # }
+
+ # Private key decryption passphrase for a key in the ecdsa folder.
+ # ecdsa<suffix> {
+
+ # File name in the ecdsa folder for which this passphrase should be
+ # used.
+ # file =
+
+ # Value of decryption passphrase for ECDSA key.
+ # secret =
+
+ # }
+
+ # Private key decryption passphrase for a key in the pkcs8 folder.
+ # pkcs8<suffix> {
+
+ # File name in the pkcs8 folder for which this passphrase should be
+ # used.
+ # file =
+
+ # Value of decryption passphrase for PKCS#8 key.
+ # secret =
+
+ # }
+
+# }
+
+# Section defining named pools.
+# pools {
+
+ # Section defining a single pool with a unique name.
+ # <name> {
+
+ # Subnet defining addresses allocated in pool.
+ # addrs =
+
+ # Comma separated list of additional attributes from type <attr>.
+ # <attr> =
+
+ # }
+
+# }
+
diff --git a/src/swanctl/swanctl.conf.5.head.in b/src/swanctl/swanctl.conf.5.head.in
new file mode 100644
index 000000000..84f734eb9
--- /dev/null
+++ b/src/swanctl/swanctl.conf.5.head.in
@@ -0,0 +1,24 @@
+.TH SWANCTL.CONF 5 "" "@PACKAGE_VERSION@" "strongSwan"
+.SH NAME
+swanctl.conf \- swanctl configuration file
+.SH DESCRIPTION
+swanctl.conf is the configuration file used by the
+.BR swanctl (8)
+tool to load configurations and credentials into the strongSwan IKE daemon.
+
+For a description of the basic file syntax refer to
+.BR strongswan.conf (5).
+
+.SH TIME FORMATS
+For all options that define a time, the time is specified in seconds. The
+.RI "" "s" ","
+.RI "" "m" ","
+.RI "" "h" ""
+and
+.RI "" "d" ""
+suffixes explicitly define the units for seconds, minutes, hours and days,
+respectively.
+
+.SH SETTINGS
+The following settings can be used to configure connections, credentials and
+pools.
diff --git a/src/swanctl/swanctl.conf.5.main b/src/swanctl/swanctl.conf.5.main
new file mode 100644
index 000000000..3d0b0e827
--- /dev/null
+++ b/src/swanctl/swanctl.conf.5.main
@@ -0,0 +1,957 @@
+.TP
+.B connections
+.br
+Section defining IKE connection configurations.
+
+The connections section defines IKE connection configurations, each in its own
+subsections. In the keyword description below, the connection is named
+.RI "" "<conn>" ","
+but an arbitrary yet unique connection name can be chosen for each connection
+subsection.
+
+.TP
+.B connections.<conn>
+.br
+Section for an IKE connection named <conn>.
+
+.TP
+.BR connections.<conn>.version " [0]"
+IKE major version to use for connection.
+.RI "" "1" ""
+uses IKEv1 aka ISAKMP,
+.RI "" "2" ""
+uses
+IKEv2. A connection using the default of
+.RI "" "0" ""
+accepts both IKEv1 and IKEv2 as
+responder, and initiates the connection actively with IKEv2.
+
+.TP
+.BR connections.<conn>.local_addrs " [%any]"
+Local address(es) to use for IKE communication, comma separated. Takes single
+IPv4/IPv6 addresses, DNS names, CIDR subnets or IP address ranges.
+
+As initiator, the first non\-range/non\-subnet is used to initiate the connection
+from. As responder, the local destination address must match at least to one of
+the specified addresses, subnets or ranges.
+
+.TP
+.BR connections.<conn>.remote_addrs " [%any]"
+Remote address(es) to use for IKE communication, comma separated. Takes single
+IPv4/IPv6 addresses, DNS names, CIDR subnets or IP address ranges.
+
+As initiator, the first non\-range/non\-subnet is used to initiate the connection
+to. As responder, the initiator source address must match at least to one of the
+specified addresses, subnets or ranges.
+
+To initiate a connection, at least one specific address or DNS name must be
+specified.
+
+.TP
+.BR connections.<conn>.local_port " [500]"
+Local UPD port for IKE communication. By default the port of the socket backend
+is used, which is usually
+.RI "" "500" "."
+If port
+.RI "" "500" ""
+is used, automatic IKE port
+floating to port 4500 is used to work around NAT issues.
+
+Using a non\-default local IKE port requires support from the socket backend in
+use (socket\-dynamic).
+
+.TP
+.BR connections.<conn>.remote_port " [500]"
+Remote UPD port for IKE communication. If the default of port
+.RI "" "500" ""
+is used,
+automatic IKE port floating to port 4500 is used to work around NAT issues.
+
+.TP
+.BR connections.<conn>.proposals " [default]"
+A proposal is a set of algorithms. For non\-AEAD algorithms, this includes for
+IKE an encryption algorithm, an integrity algorithm, a pseudo random function
+and a Diffie\-Hellman group. For AEAD algorithms, instead of encryption and
+integrity algorithms, a combined algorithm is used.
+
+In IKEv2, multiple algorithms of the same kind can be specified in a single
+proposal, from which one gets selected. In IKEv1, only one algorithm per kind is
+allowed per proposal, more algorithms get implicitly stripped. Use multiple
+proposals to offer different algorithms combinations in IKEv1.
+
+Algorithm keywords get separated using dashes. Multiple proposals may be
+separated by commas. The special value
+.RI "" "default" ""
+forms a default proposal of
+supported algorithms considered safe, and is usually a good choice for
+interoperability.
+
+.TP
+.BR connections.<conn>.vips " []"
+Comma separated list of virtual IPs to request in IKEv2 configuration payloads
+or IKEv1 Mode Config. The wildcard addresses
+.RI "" "0.0.0.0" ""
+and
+.RI "" "::" ""
+request an
+arbitrary address, specific addresses may be defined. The responder may return a
+different address, though, or none at all.
+
+.TP
+.BR connections.<conn>.aggressive " [no]"
+Enables Aggressive Mode instead of Main Mode with Identity Protection.
+Aggressive Mode is considered less secure, because the ID and HASH payloads are
+exchanged unprotected. This allows a passive attacker to snoop peer identities,
+and even worse, start dictionary attacks on the Preshared Key.
+
+.TP
+.BR connections.<conn>.pull " [yes]"
+If the default of
+.RI "" "yes" ""
+is used, Mode Config works in pull mode, where the
+initiator actively requests a virtual IP. With
+.RI "" "no" ","
+push mode is used, where
+the responder pushes down a virtual IP to the initiating peer.
+
+Push mode is currently supported for IKEv1, but not in IKEv2. It is used by a
+few implementations only, pull mode is recommended.
+
+.TP
+.BR connections.<conn>.encap " [no]"
+To enforce UDP encapsulation of ESP packets, the IKE daemon can fake the NAT
+detection payloads. This makes the peer believe that NAT takes place on the
+path, forcing it to encapsulate ESP packets in UDP.
+
+Usually this is not required, but it can help to work around connectivity issues
+with too restrictive intermediary firewalls.
+
+.TP
+.BR connections.<conn>.mobike " [yes]"
+Enables MOBIKE on IKEv2 connections. MOBIKE is enabled by default on IKEv2
+connections, and allows mobility of clients and multi\-homing on servers by
+migrating active IPsec tunnels.
+
+Usually keeping MOBIKE enabled is unproblematic, as it is not used if the peer
+does not indicate support for it. However, due to the design of MOBIKE, IKEv2
+always floats to port 4500 starting from the second exchange. Some
+implementations don't like this behavior, hence it can be disabled.
+
+.TP
+.BR connections.<conn>.dpd_delay " [0s]"
+Interval to check the liveness of a peer actively using IKEv2 INFORMATIONAL
+exchanges or IKEv1 R_U_THERE messages. Active DPD checking is only enforced if
+no IKE or ESP/AH packet has been received for the configured DPD delay.
+
+.TP
+.BR connections.<conn>.dpd_timeout " [0s]"
+Charon by default uses the normal retransmission mechanism and timeouts to check
+the liveness of a peer, as all messages are used for liveness checking. For
+compatibility reasons, with IKEv1 a custom interval may be specified; this
+option has no effect on connections using IKE2.
+
+.TP
+.BR connections.<conn>.fragmentation " [no]"
+The default of
+.RI "" "no" ""
+disables IKEv1 fragmentation mechanism,
+.RI "" "yes" ""
+enables it if
+support has been indicated by the peer.
+.RI "" "force" ""
+enforces fragmentation if
+required even before the peer had a chance to indicate support for it.
+
+IKE fragmentation is currently not supported with IKEv2.
+
+.TP
+.BR connections.<conn>.send_certreq " [yes]"
+Send certificate request payloads to offer trusted root CA certificates to the
+peer. Certificate requests help the peer to choose an appropriate
+certificate/private key for authentication and are enabled by default.
+
+Disabling certificate requests can be useful if too many trusted root CA
+certificates are installed, as each certificate request increases the size of
+the initial IKE packets.
+
+.TP
+.BR connections.<conn>.send_cert " [ifasked]"
+Send certificate payloads when using certificate authentication. With the
+default of
+.RI "" "ifasked" ""
+the daemon sends certificate payloads only if certificate
+requests have been received.
+.RI "" "no" ""
+disables sending of certificate payloads,
+.RI "" "yes" ""
+always sends certificate payloads whenever certificate authentication is
+used.
+
+.TP
+.BR connections.<conn>.keyingtries " [1]"
+Number of retransmission sequences to perform during initial connect. Instead of
+giving up initiation after the first retransmission sequence with the default
+value of
+.RI "" "1" ","
+additional sequences may be started according to the configured
+value. A value of
+.RI "" "0" ""
+initiates a new sequence until the connection establishes
+or fails with a permanent error.
+
+.TP
+.BR connections.<conn>.unique " [no]"
+Connection uniqueness policy to enforce. To avoid multiple connections from the
+same user, a uniqueness policy can be enforced. The value
+.RI "" "never" ""
+does never
+enforce such a policy, even if a peer included INITIAL_CONTACT notification
+messages, whereas
+.RI "" "no" ""
+replaces existing connections for the same identity if a
+new one has the INITIAL_CONTACT notify.
+.RI "" "keep" ""
+rejects new connection attempts
+if the same user already has an active connection,
+.RI "" "replace" ""
+deletes any
+existing connection if a new one for the same user gets established.
+
+To compare connections for uniqueness, the remote IKE identity is used. If EAP
+or XAuth authentication is involved, the EAP\-Identity or XAuth username is used
+to enforce the uniqueness policy instead.
+
+.TP
+.BR connections.<conn>.reauth_time " [0s]"
+Time to schedule IKE reauthentication. IKE reauthentication recreates the
+IKE/ISAKMP SA from scratch and re\-evaluates the credentials. In asymmetric
+configurations (with EAP or configuration payloads) it might not be possible to
+actively reauthenticate as responder. The IKEv2 reauthentication lifetime
+negotiation can instruct the client to perform reauthentication.
+
+Reauthentication is disabled by default. Enabling it usually may lead to small
+connection interruptions, as strongSwan uses a break\-before\-make policy with
+IKEv2 to avoid any conflicts with associated tunnel resources.
+
+.TP
+.BR connections.<conn>.rekey_time " [4h]"
+IKE rekeying refreshes key material using a Diffie\-Hellman exchange, but does
+not re\-check associated credentials. It is supported in IKEv2 only, IKEv1
+performs a reauthentication procedure instead.
+
+With the default value IKE rekeying is scheduled every 4 hours, minus the
+configured
+.RB "" "rand_time" "."
+
+
+.TP
+.BR connections.<conn>.over_time " [10% of rekey_time/reauth_time]"
+Hard IKE_SA lifetime if rekey/reauth does not complete, as time. To avoid having
+an IKE/ISAKMP kept alive if IKE reauthentication or rekeying fails perpetually,
+a maximum hard lifetime may be specified. If the IKE_SA fails to rekey or
+reauthenticate within the specified time, the IKE_SA gets closed.
+
+In contrast to CHILD_SA rekeying,
+.RB "" "over_time" ""
+is relative in time to the
+.RB "" "rekey_time" ""
+.RI "" "and" ""
+.RB "" "reauth_time" ""
+values, as it applies to both.
+
+The default is 10% of the longer of
+.RB "" "rekey_time" ""
+and
+.RB "" "reauth_time" "."
+
+
+.TP
+.BR connections.<conn>.rand_time " [over_time]"
+Time range from which to choose a random value to subtract from rekey/reauth
+times. To avoid having both peers initiating the rekey/reauth procedure
+simultaneously, a random time gets subtracted from the rekey/reauth times.
+
+The default is equal to the configured
+.RB "" "over_time" "."
+
+
+.TP
+.BR connections.<conn>.pools " []"
+Comma separated list of named IP pools to allocate virtual IP addresses and
+other configuration attributes from. Each name references a pool by name from
+either the
+.RB "" "pools" ""
+section or an external pool.
+
+.TP
+.B connections.<conn>.local<suffix>
+.br
+Section for a local authentication round. A local authentication round defines
+the rules how authentication is performed for the local peer. Multiple rounds
+may be defined to use IKEv2 RFC 4739 Multiple Authentication or IKEv1 XAuth.
+
+Each round is defined in a section having
+.RI "" "local" ""
+as prefix, and an optional
+unique suffix. To define a single authentication round, the suffix may be
+omitted.
+
+.TP
+.BR connections.<conn>.local<suffix>.certs " []"
+Comma separated list of certificate candidates to use for authentication. The
+certificates may use a relative path from the
+.RB "" "swanctl" ""
+.RI "" "x509" ""
+directory, or
+an absolute path.
+
+The certificate used for authentication is selected based on the received
+certificate request payloads. If no appropriate CA can be located, the first
+certificate is used.
+
+.TP
+.BR connections.<conn>.local<suffix>.auth " [pubkey]"
+Authentication to perform locally.
+.RI "" "pubkey" ""
+uses public key authentication using
+a private key associated to a usable certificate.
+.RI "" "psk" ""
+uses pre\-shared key
+authentication. The IKEv1 specific
+.RI "" "xauth" ""
+is used for XAuth or Hybrid
+authentication, while the IKEv2 specific
+.RI "" "eap" ""
+keyword defines EAP
+authentication.
+
+For
+.RI "" "xauth" ","
+a specific backend name may be appended, separated by a dash. The
+appropriate
+.RI "" "xauth" ""
+backend is selected to perform the XAuth exchange. For
+traditional XAuth, the
+.RI "" "xauth" ""
+method is usually defined in the second
+authentication round following an initial
+.RI "" "pubkey" ""
+(or
+.RI "" "psk" ")"
+round. Using
+.RI "" "xauth" ""
+in the first round performs Hybrid Mode client authentication.
+
+For
+.RI "" "eap" ","
+a specific EAP method name may be appended, separated by a dash. An
+EAP module implementing the appropriate method is selected to perform the EAP
+conversation.
+
+.TP
+.BR connections.<conn>.local<suffix>.id " []"
+IKE identity to use for authentication round. When using certificate
+authentication, the IKE identity must be contained in the certificate, either as
+subject or as subjectAltName.
+
+.TP
+.BR connections.<conn>.local<suffix>.eap_id " [id]"
+Client EAP\-Identity to use in EAP\-Identity exchange and the EAP method.
+
+.TP
+.BR connections.<conn>.local<suffix>.aaa_id " [remote-id]"
+Server side EAP\-Identity to expect in the EAP method. Some EAP methods, such as
+EAP\-TLS, use an identity for the server to perform mutual authentication. This
+identity may differ from the IKE identity, especially when EAP authentication is
+delegated from the IKE responder to an AAA backend.
+
+For EAP\-(T)TLS, this defines the identity for which the server must provide a
+certificate in the TLS exchange.
+
+.TP
+.BR connections.<conn>.local<suffix>.xauth_id " [id]"
+Client XAuth username used in the XAuth exchange.
+
+.TP
+.B connections.<conn>.remote<suffix>
+.br
+Section for a remote authentication round. A remote authentication round defines
+the constraints how the peers must authenticate to use this connection. Multiple
+rounds may be defined to use IKEv2 RFC 4739 Multiple Authentication or IKEv1
+XAuth.
+
+Each round is defined in a section having
+.RI "" "remote" ""
+as prefix, and an optional
+unique suffix. To define a single authentication round, the suffix may be
+omitted.
+
+.TP
+.BR connections.<conn>.remote<suffix>.id " [%any]"
+IKE identity to expect for authentication round. When using certificate
+authentication, the IKE identity must be contained in the certificate, either as
+subject or as subjectAltName.
+
+.TP
+.BR connections.<conn>.remote<suffix>.groups " []"
+Comma separated authorization group memberships to require. The peer must prove
+membership to at least one of the specified groups. Group membership can be
+certified by different means, for example by appropriate Attribute Certificates
+or by an AAA backend involved in the authentication.
+
+.TP
+.BR connections.<conn>.remote<suffix>.certs " []"
+Comma separated list of certificates to accept for authentication. The
+certificates may use a relative path from the
+.RB "" "swanctl" ""
+.RI "" "x509" ""
+directory, or
+an absolute path.
+
+.TP
+.BR connections.<conn>.remote<suffix>.cacert " []"
+Comma separated list of CA certificates to accept for authentication. The
+certificates may use a relative path from the
+.RB "" "swanctl" ""
+.RI "" "x509ca" ""
+directory, or
+an absolute path.
+
+.TP
+.BR connections.<conn>.remote<suffix>.revocation " [relaxed]"
+Certificate revocation policy for CRL or OCSP revocation.
+
+A
+.RI "" "strict" ""
+revocation policy fails if no revocation information is available,
+i.e. the certificate is not known to be unrevoked.
+
+.RI "" "ifuri" ""
+fails only if a CRL/OCSP URI is available, but certificate revocation
+checking fails, i.e. there should be revocation information available, but it
+could not be obtained.
+
+The default revocation policy
+.RI "" "relaxed" ""
+fails only if a certificate is revoked,
+i.e. it is explicitly known that it is bad.
+
+.TP
+.BR connections.<conn>.remote<suffix>.auth " [pubkey]"
+Authentication to expect from remote. See the
+.RB "" "local" ""
+sections
+.RB "" "auth" ""
+keyword description about the details of supported mechanisms.
+
+.TP
+.B connections.<conn>.children.<child>
+.br
+CHILD_SA configuration sub\-section. Each connection definition may have one or
+more sections in its
+.RI "" "children" ""
+subsection. The section name defines the name of
+the CHILD_SA configuration, which must be unique within the connection.
+
+.TP
+.BR connections.<conn>.children.<child>.ah_proposals " []"
+AH proposals to offer for the CHILD_SA. A proposal is a set of algorithms. For
+AH, this includes an integrity algorithm and an optional Diffie\-Hellman group.
+If a DH group is specified, CHILD_SA/Quick Mode rekeying and initial negotiation
+uses a separate Diffie\-Hellman exchange using the specified group.
+
+In IKEv2, multiple algorithms of the same kind can be specified in a single
+proposal, from which one gets selected. In IKEv1, only one algorithm per kind is
+allowed per proposal, more algorithms get implicitly stripped. Use multiple
+proposals to offer different algorithms combinations in IKEv1.
+
+Algorithm keywords get separated using dashes. Multiple proposals may be
+separated by commas. The special value
+.RI "" "default" ""
+forms a default proposal of
+supported algorithms considered safe, and is usually a good choice for
+interoperability. By default no AH proposals are included, instead ESP is
+proposed.
+
+.TP
+.BR connections.<conn>.children.<child>.esp_proposals " [default]"
+ESP proposals to offer for the CHILD_SA. A proposal is a set of algorithms. For
+ESP non\-AEAD proposals, this includes an integrity algorithm, an encryption
+algorithm, an optional Diffie\-Hellman group and an optional Extended Sequence
+Number Mode indicator. For AEAD proposals, a combined mode algorithm is used
+instead of the separate encryption/integrity algorithms.
+
+If a DH group is specified, CHILD_SA/Quick Mode rekeying and initial (non
+IKE_AUTH piggybacked) negotiation uses a separate Diffie\-Hellman exchange using
+the specified group. Extended Sequence Number support may be indicated with the
+.RI "" "esn" ""
+and
+.RI "" "noesn" ""
+values, both may be included to indicate support for both
+modes. If omitted,
+.RI "" "noesn" ""
+is assumed.
+
+In IKEv2, multiple algorithms of the same kind can be specified in a single
+proposal, from which one gets selected. In IKEv1, only one algorithm per kind is
+allowed per proposal, more algorithms get implicitly stripped. Use multiple
+proposals to offer different algorithms combinations in IKEv1.
+
+Algorithm keywords get separated using dashes. Multiple proposals may be
+separated by commas. The special value
+.RI "" "default" ""
+forms a default proposal of
+supported algorithms considered safe, and is usually a good choice for
+interoperability. If no algorithms are specified for AH nor ESP, the
+.RI "" "default" ""
+set of algorithms for ESP is included.
+
+.TP
+.BR connections.<conn>.children.<child>.local_ts " [dynamic]"
+Comma separated list of local traffic selectors to include in CHILD_SA. Each
+selector is a CIDR subnet definition, followed by an optional proto/port
+selector. The special value
+.RI "" "dynamic" ""
+may be used instead of a subnet
+definition, which gets replaced by the tunnel outer address or the virtual IP,
+if negotiated. This is the default.
+
+A protocol/port selector is surrounded by opening and closing square brackets.
+Between these brackets, a numeric or
+.RB "" "getservent" "(3)"
+protocol name may be
+specified. After the optional protocol restriction, an optional port restriction
+may be specified, separated by a slash. The port restriction may be numeric, a
+.RB "" "getservent" "(3)"
+service name, or the special value
+.RI "" "opaque" ""
+for RFC 4301
+OPAQUE selectors. Port ranges may be specified as well, none of the kernel
+backends currently support port ranges, though.
+
+Unless the Unity extension is used, IKEv1 supports the first specified selector
+only. IKEv1 uses very similar traffic selector narrowing as it is supported in
+the IKEv2 protocol.
+
+.TP
+.BR connections.<conn>.children.<child>.remote_ts " [dynamic]"
+Comma separated list of remote selectors to include in CHILD_SA. See
+.RB "" "local_ts" ""
+for a description of the selector syntax.
+
+.TP
+.BR connections.<conn>.children.<child>.rekey_time " [1h]"
+Time to schedule CHILD_SA rekeying. CHILD_SA rekeying refreshes key material,
+optionally using a Diffie\-Hellman exchange if a group is specified in the
+proposal.
+
+To avoid rekey collisions initiated by both ends simultaneously, a value in the
+range of
+.RB "" "rand_time" ""
+gets subtracted to form the effective soft lifetime.
+
+By default CHILD_SA rekeying is scheduled every hour, minus
+.RB "" "rand_time" "."
+
+
+.TP
+.BR connections.<conn>.children.<child>.life_time " [rekey_time + 10%]"
+Maximum lifetime before CHILD_SA gets closed. Usually this hard lifetime is
+never reached, because the CHILD_SA gets rekeyed before. If that fails for
+whatever reason, this limit closes the CHILD_SA.
+
+The default is 10% more than the
+.RB "" "rekey_time" "."
+
+
+.TP
+.BR connections.<conn>.children.<child>.rand_time " [life_time - rekey_time]"
+Time range from which to choose a random value to subtract from
+.RB "" "rekey_time" "."
+The default is the difference between
+.RB "" "life_time" ""
+and
+.RB "" "rekey_time" "."
+
+
+.TP
+.BR connections.<conn>.children.<child>.rekey_bytes " [0]"
+Number of bytes processed before initiating CHILD_SA rekeying. CHILD_SA rekeying
+refreshes key material, optionally using a Diffie\-Hellman exchange if a group is
+specified in the proposal.
+
+To avoid rekey collisions initiated by both ends simultaneously, a value in the
+range of
+.RB "" "rand_bytes" ""
+gets subtracted to form the effective soft volume limit.
+
+Volume based CHILD_SA rekeying is disabled by default.
+
+.TP
+.BR connections.<conn>.children.<child>.life_bytes " [rekey_bytes + 10%]"
+Maximum bytes processed before CHILD_SA gets closed. Usually this hard volume
+limit is never reached, because the CHILD_SA gets rekeyed before. If that fails
+for whatever reason, this limit closes the CHILD_SA.
+
+The default is 10% more than
+.RB "" "rekey_bytes" "."
+
+
+.TP
+.BR connections.<conn>.children.<child>.rand_bytes " [life_bytes - rekey_bytes]"
+Byte range from which to choose a random value to subtract from
+.RB "" "rekey_bytes" "."
+The default is the difference between
+.RB "" "life_bytes" ""
+and
+.RB "" "rekey_bytes" "."
+
+
+.TP
+.BR connections.<conn>.children.<child>.rekey_packets " [0]"
+Number of packets processed before initiating CHILD_SA rekeying. CHILD_SA
+rekeying refreshes key material, optionally using a Diffie\-Hellman exchange if a
+group is specified in the proposal.
+
+To avoid rekey collisions initiated by both ends simultaneously, a value in the
+range of
+.RB "" "rand_packets" ""
+gets subtracted to form the effective soft packet
+count limit.
+
+Packet count based CHILD_SA rekeying is disabled by default.
+
+.TP
+.BR connections.<conn>.children.<child>.life_packets " [rekey_packets + 10%]"
+Maximum number of packets processed before CHILD_SA gets closed. Usually this
+hard packets limit is never reached, because the CHILD_SA gets rekeyed before.
+If that fails for whatever reason, this limit closes the CHILD_SA.
+
+The default is 10% more than
+.RB "" "rekey_bytes" "."
+
+
+.TP
+.BR connections.<conn>.children.<child>.rand_packets " [life_packets - rekey_packets]"
+Packet range from which to choose a random value to subtract from
+.RB "" "rekey_packets" "."
+The default is the difference between
+.RB "" "life_packets" ""
+and
+.RB "" "rekey_packets" "."
+
+
+.TP
+.BR connections.<conn>.children.<child>.updown " []"
+Updown script to invoke on CHILD_SA up and down events.
+
+.TP
+.BR connections.<conn>.children.<child>.hostaccess " [yes]"
+Hostaccess variable to pass to
+.RB "" "updown" ""
+script.
+
+.TP
+.BR connections.<conn>.children.<child>.mode " [tunnel]"
+IPsec Mode to establish CHILD_SA with.
+.RI "" "tunnel" ""
+negotiates the CHILD_SA in IPsec
+Tunnel Mode, whereas
+.RI "" "transport" ""
+uses IPsec Transport Mode.
+.RI "" "beet" ""
+is the Bound
+End to End Tunnel mixture mode, working with fixed inner addresses without the
+need to include them in each packet.
+
+Both
+.RI "" "transport" ""
+and
+.RI "" "beet" ""
+modes are subject to mode negotiation;
+.RI "" "tunnel" ""
+mode
+is negotiated if the preferred mode is not available.
+
+.RI "" "pass" ""
+and
+.RI "" "drop" ""
+are used to install shunt policies, which explicitly bypass
+the defined traffic from IPsec processing, or drop it, respectively.
+
+.TP
+.BR connections.<conn>.children.<child>.dpd_action " [clear]"
+Action to perform for this CHILD_SA on DPD timeout. The default
+.RI "" "clear" ""
+closes
+the CHILD_SA and does not take further action.
+.RI "" "trap" ""
+installs a trap policy,
+which will catch matching traffic and tries to re\-negotiate the tunnel
+on\-demand.
+.RI "" "restart" ""
+immediately tries to re\-negotiate the CHILD_SA under a
+fresh IKE_SA.
+
+.TP
+.BR connections.<conn>.children.<child>.ipcomp " [no]"
+Enable IPComp compression before encryption. If enabled, IKE tries to negotiate
+IPComp compression to compress ESP payload data prior to encryption.
+
+.TP
+.BR connections.<conn>.children.<child>.inactivity " [0s]"
+Timeout before closing CHILD_SA after inactivity. If no traffic has been
+processed in either direction for the configured timeout, the CHILD_SA gets
+closed due to inactivity. The default value of
+.RI "" "0" ""
+disables inactivity checks.
+
+.TP
+.BR connections.<conn>.children.<child>.reqid " [0]"
+Fixed reqid to use for this CHILD_SA. This might be helpful in some scenarios,
+but works only if each CHILD_SA configuration is instantiated not more than
+once. The default of
+.RI "" "0" ""
+uses dynamic reqids, allocated incrementally.
+
+.TP
+.BR connections.<conn>.children.<child>.mark_in " [0/0x00000000]"
+Netfilter mark and mask for input traffic. On Linux Netfilter may apply marks to
+each packet coming from a tunnel having that option set. The mark may then be
+used by Netfilter to match rules.
+
+An additional mask may be appended to the mark, separated by _/_. The default
+mask if omitted is 0xffffffff.
+
+.TP
+.BR connections.<conn>.children.<child>.mark_out " [0/0x00000000]"
+Netfilter mark and mask for output traffic. On Linux Netfilter may require marks
+on each packet to match a policy having that option set. This allows Netfilter
+rules to select specific tunnels for outgoing traffic.
+
+An additional mask may be appended to the mark, separated by _/_. The default
+mask if omitted is 0xffffffff.
+
+.TP
+.BR connections.<conn>.children.<child>.tfc_padding " [0]"
+Pads ESP packets with additional data to have a consistent ESP packet size for
+improved Traffic Flow Confidentiality. The padding defines the minimum size of
+all ESP packets sent.
+
+The default value of 0 disables TFC padding, the special value
+.RI "" "mtu" ""
+adds TFC
+padding to create a packet size equal to the Path Maximum Transfer Unit.
+
+.TP
+.BR connections.<conn>.children.<child>.replay_window " [32]"
+IPsec replay window to configure for this CHILD_SA. Larger values than the
+default of 32 are supported using the Netlink backend only, a value of 0
+disables IPsec replay protection.
+
+.TP
+.BR connections.<conn>.children.<child>.start_action " [none]"
+Action to perform after loading the configuration. The default of
+.RI "" "none" ""
+loads
+the connection only, which then can be manually initiated or used as a responder
+configuration.
+
+The value
+.RI "" "trap" ""
+installs a trap policy, which triggers the tunnel as soon as
+matching traffic has been detected. The value
+.RI "" "start" ""
+initiates the connection
+actively.
+
+When unloading or replacing a CHILD_SA configuration having a
+.RB "" "start_action" ""
+different from
+.RI "" "none" ","
+the inverse action is performed. Configurations with
+.RI "" "start" ""
+get closed, while such with
+.RI "" "trap" ""
+get uninstalled.
+
+.TP
+.BR connections.<conn>.children.<child>.close_action " [none]"
+Action to perform after a CHILD_SA gets closed by the peer. The default of
+.RI "" "none" ""
+does not take any action,
+.RI "" "trap" ""
+installs a trap policy for the CHILD_SA.
+.RI "" "start" ""
+tries to re\-create the CHILD_SA.
+
+.RB "" "close_action" ""
+does not provide any guarantee that the CHILD_SA is kept alive.
+It acts on explicit close messages only, but not on negotiation failures. Use
+trap policies to reliably re\-create failed CHILD_SAs.
+
+.TP
+.B secrets
+.br
+Section defining secrets for IKE/EAP/XAuth authentication and private key
+decryption. The
+.RB "" "secrets" ""
+section takes sub\-sections having a specific prefix
+which defines the secret type.
+
+It is not recommended to define any private key decryption passphrases, as then
+there is no real security benefit in having encrypted keys. Either store the key
+unencrypted, or enter the keys manually when loading credentials.
+
+.TP
+.B secrets.eap<suffix>
+.br
+EAP secret section for a specific secret. Each EAP secret is defined in a unique
+section having the
+.RI "" "eap" ""
+prefix. EAP secrets are used for XAuth authentication
+as well.
+
+.TP
+.BR secrets.eap<suffix>.secret " []"
+Value of the EAP/XAuth secret. It may either be an ASCII string, a hex encoded
+string if it has a
+.RI "" "0x" ""
+prefix, or a Base64 encoded string if it has a
+.RI "" "0s" ""
+prefix in its value.
+
+.TP
+.BR secrets.eap<suffix>.id<suffix> " []"
+Identity the EAP/XAuth secret belongs to. Multiple unique identities may be
+specified, each having an
+.RI "" "id" ""
+prefix, if a secret is shared between multiple
+users.
+
+.TP
+.B secrets.xauth<suffix>
+.br
+XAuth secret section for a specific secret.
+.RB "" "xauth" ""
+is just an alias for
+.RB "" "eap" ","
+secrets under both section prefixes are used for both EAP and XAuth
+authentication.
+
+.TP
+.B secrets.ike<suffix>
+.br
+IKE preshared secret section for a specific secret. Each IKE PSK is defined in a
+unique section having the
+.RI "" "ike" ""
+prefix.
+
+.TP
+.BR secrets.ike<suffix>.secret " []"
+Value of the IKE preshared secret. It may either be an ASCII string, a hex
+encoded string if it has a
+.RI "" "0x" ""
+prefix, or a Base64 encoded string if it has a
+.RI "" "0s" ""
+prefix in its value.
+
+.TP
+.BR secrets.ike<suffix>.id<suffix> " []"
+IKE identity the IKE preshared secret belongs to. Multiple unique identities may
+be specified, each having an
+.RI "" "id" ""
+prefix, if a secret is shared between multiple
+peers.
+
+.TP
+.B secrets.rsa<suffix>
+.br
+Private key decryption passphrase for a key in the
+.RI "" "rsa" ""
+folder.
+
+.TP
+.BR secrets.rsa<suffix>.file " []"
+File name in the
+.RI "" "rsa" ""
+folder for which this passphrase should be used.
+
+.TP
+.BR secrets.rsa<suffix>.secret " []"
+Value of decryption passphrase for RSA key.
+
+.TP
+.B secrets.ecdsa<suffix>
+.br
+Private key decryption passphrase for a key in the
+.RI "" "ecdsa" ""
+folder.
+
+.TP
+.BR secrets.ecdsa<suffix>.file " []"
+File name in the
+.RI "" "ecdsa" ""
+folder for which this passphrase should be used.
+
+.TP
+.BR secrets.ecdsa<suffix>.secret " []"
+Value of decryption passphrase for ECDSA key.
+
+.TP
+.B secrets.pkcs8<suffix>
+.br
+Private key decryption passphrase for a key in the
+.RI "" "pkcs8" ""
+folder.
+
+.TP
+.BR secrets.pkcs8<suffix>.file " []"
+File name in the
+.RI "" "pkcs8" ""
+folder for which this passphrase should be used.
+
+.TP
+.BR secrets.pkcs8<suffix>.secret " []"
+Value of decryption passphrase for PKCS#8 key.
+
+.TP
+.B pools
+.br
+Section defining named pools. Named pools may be referenced by connections with
+the
+.RB "" "pools" ""
+option to assign virtual IPs and other configuration attributes.
+
+.TP
+.B pools.<name>
+.br
+Section defining a single pool with a unique name.
+
+.TP
+.BR pools.<name>.addrs " []"
+Subnet defining addresses allocated in pool. Accepts a single CIDR subnet
+defining the pool to allocate addresses from. Pools must be unique and
+non\-overlapping.
+
+.TP
+.BR pools.<name>.<attr> " []"
+Comma separated list of additional attributes of type
+.RB "" "<attr>" "."
+The attribute
+type may be one of
+.RI "" "dns" ","
+.RI "" "nbns" ","
+.RI "" "dhcp" ","
+.RI "" "netmask" ","
+.RI "" "server" ","
+.RI "" "subnet" ","
+.RI "" "split_include" ""
+and
+.RI "" "split_exclude" ""
+to define addresses or CIDR subnets for the
+corresponding attribute types. Alternatively,
+.RB "" "<attr>" ""
+can be a numerical
+identifier, for which string attribute values are accepted as well.
+
diff --git a/src/swanctl/swanctl.conf.5.tail.in b/src/swanctl/swanctl.conf.5.tail.in
new file mode 100644
index 000000000..4d24608da
--- /dev/null
+++ b/src/swanctl/swanctl.conf.5.tail.in
@@ -0,0 +1,10 @@
+.SH FILES
+.
+.nf
+.na
+/etc/swanctl/swanctl.conf configuration file
+.ad
+.fi
+.
+.SH SEE ALSO
+.BR swanctl (8)
diff --git a/src/swanctl/swanctl.h b/src/swanctl/swanctl.h
new file mode 100644
index 000000000..bd7e00378
--- /dev/null
+++ b/src/swanctl/swanctl.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup swanctl swanctl
+ * @{
+ */
+
+#ifndef SWANCTL_H_
+#define SWANCTL_H_
+
+/**
+ * Configuration file for connections, etc.
+ */
+#define SWANCTL_CONF SWANCTLDIR "/swanctl.conf"
+
+/**
+ * Directory for X.509 end entity certs
+ */
+#define SWANCTL_X509DIR SWANCTLDIR "/x509"
+
+/**
+ * Directory for X.509 CA certs
+ */
+#define SWANCTL_X509CADIR SWANCTLDIR "/x509ca"
+
+/**
+ * Directory for X.509 Attribute Authority certs
+ */
+#define SWANCTL_X509AADIR SWANCTLDIR "/x509aa"
+
+/**
+ * Directory for X.509 CRLs
+ */
+#define SWANCTL_X509CRLDIR SWANCTLDIR "/x509crl"
+
+/**
+ * Directory for X.509 Attribute certificates
+ */
+#define SWANCTL_X509ACDIR SWANCTLDIR "/x509ac"
+
+/**
+ * Directory for RSA private keys
+ */
+#define SWANCTL_RSADIR SWANCTLDIR "/rsa"
+
+/**
+ * Directory for ECDSA private keys
+ */
+#define SWANCTL_ECDSADIR SWANCTLDIR "/ecdsa"
+
+/**
+ * Directory for PKCS#8 encoded private keys
+ */
+#define SWANCTL_PKCS8DIR SWANCTLDIR "/pkcs8"
+
+#endif /** SWANCTL_H_ @}*/
diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt
new file mode 100644
index 000000000..e136ffb5b
--- /dev/null
+++ b/src/swanctl/swanctl.opt
@@ -0,0 +1,779 @@
+connections { # }
+ Section defining IKE connection configurations.
+
+ Section defining IKE connection configurations.
+
+ The connections section defines IKE connection configurations, each in
+ its own subsections. In the keyword description below, the connection
+ is named _<conn>_, but an arbitrary yet unique connection name can be
+ chosen for each connection subsection.
+
+connections.<conn> { # }
+ Section for an IKE connection named <conn>.
+
+connections.<conn>.version = 0
+ IKE major version to use for connection.
+
+ IKE major version to use for connection. _1_ uses IKEv1 aka ISAKMP, _2_
+ uses IKEv2. A connection using the default of _0_ accepts both IKEv1
+ and IKEv2 as responder, and initiates the connection actively with IKEv2.
+
+connections.<conn>.local_addrs = %any
+ Local address(es) to use for IKE communication, comma separated.
+
+ Local address(es) to use for IKE communication, comma separated. Takes
+ single IPv4/IPv6 addresses, DNS names, CIDR subnets or IP address ranges.
+
+ As initiator, the first non-range/non-subnet is used to initiate the
+ connection from. As responder, the local destination address must match at
+ least to one of the specified addresses, subnets or ranges.
+
+connections.<conn>.remote_addrs = %any
+ Remote address(es) to use for IKE communication, comma separated.
+
+ Remote address(es) to use for IKE communication, comma separated. Takes
+ single IPv4/IPv6 addresses, DNS names, CIDR subnets or IP address ranges.
+
+ As initiator, the first non-range/non-subnet is used to initiate the
+ connection to. As responder, the initiator source address must match at
+ least to one of the specified addresses, subnets or ranges.
+
+ To initiate a connection, at least one specific address or DNS name must
+ be specified.
+
+connections.<conn>.local_port = 500
+ Local UPD port for IKE communication.
+
+ Local UPD port for IKE communication. By default the port of the socket
+ backend is used, which is usually _500_. If port _500_ is used, automatic
+ IKE port floating to port 4500 is used to work around NAT issues.
+
+ Using a non-default local IKE port requires support from the socket backend
+ in use (socket-dynamic).
+
+connections.<conn>.remote_port = 500
+ Remote UDP port for IKE communication.
+
+ Remote UPD port for IKE communication. If the default of port _500_ is used,
+ automatic IKE port floating to port 4500 is used to work around NAT issues.
+
+connections.<conn>.proposals = default
+ Comma separated proposals to accept for IKE.
+
+ A proposal is a set of algorithms. For non-AEAD algorithms, this includes
+ for IKE an encryption algorithm, an integrity algorithm, a pseudo random
+ function and a Diffie-Hellman group. For AEAD algorithms, instead of
+ encryption and integrity algorithms, a combined algorithm is used.
+
+ In IKEv2, multiple algorithms of the same kind can be specified in a single
+ proposal, from which one gets selected. In IKEv1, only one algorithm per
+ kind is allowed per proposal, more algorithms get implicitly stripped. Use
+ multiple proposals to offer different algorithms combinations in IKEv1.
+
+ Algorithm keywords get separated using dashes. Multiple proposals may be
+ separated by commas. The special value _default_ forms a default proposal
+ of supported algorithms considered safe, and is usually a good choice
+ for interoperability.
+
+connections.<conn>.vips =
+ Virtual IPs to request in configuration payload / Mode Config.
+
+ Comma separated list of virtual IPs to request in IKEv2 configuration
+ payloads or IKEv1 Mode Config. The wildcard addresses _0.0.0.0_ and _::_
+ request an arbitrary address, specific addresses may be defined. The
+ responder may return a different address, though, or none at all.
+
+connections.<conn>.aggressive = no
+ Use Aggressive Mode in IKEv1.
+
+ Enables Aggressive Mode instead of Main Mode with Identity Protection.
+ Aggressive Mode is considered less secure, because the ID and HASH
+ payloads are exchanged unprotected. This allows a passive attacker to
+ snoop peer identities, and even worse, start dictionary attacks on the
+ Preshared Key.
+
+connections.<conn>.pull = yes
+ Set the Mode Config mode to use.
+
+ If the default of _yes_ is used, Mode Config works in pull mode, where
+ the initiator actively requests a virtual IP. With _no_, push mode is used,
+ where the responder pushes down a virtual IP to the initiating peer.
+
+ Push mode is currently supported for IKEv1, but not in IKEv2. It is used
+ by a few implementations only, pull mode is recommended.
+
+connections.<conn>.encap = no
+ Enforce UDP encapsulation by faking NAT-D payloads.
+
+ To enforce UDP encapsulation of ESP packets, the IKE daemon can fake the
+ NAT detection payloads. This makes the peer believe that NAT takes
+ place on the path, forcing it to encapsulate ESP packets in UDP.
+
+ Usually this is not required, but it can help to work around connectivity
+ issues with too restrictive intermediary firewalls.
+
+connections.<conn>.mobike = yes
+ Enables MOBIKE on IKEv2 connections.
+
+ Enables MOBIKE on IKEv2 connections. MOBIKE is enabled by default on IKEv2
+ connections, and allows mobility of clients and multi-homing on servers by
+ migrating active IPsec tunnels.
+
+ Usually keeping MOBIKE enabled is unproblematic, as it is not used if the
+ peer does not indicate support for it. However, due to the design of MOBIKE,
+ IKEv2 always floats to port 4500 starting from the second exchange. Some
+ implementations don't like this behavior, hence it can be disabled.
+
+connections.<conn>.dpd_delay = 0s
+ Interval of liveness checks (DPD).
+
+ Interval to check the liveness of a peer actively using IKEv2 INFORMATIONAL
+ exchanges or IKEv1 R_U_THERE messages. Active DPD checking is only enforced
+ if no IKE or ESP/AH packet has been received for the configured DPD delay.
+
+connections.<conn>.dpd_timeout = 0s
+ Timeout for DPD checks (IKEV1 only).
+
+ Charon by default uses the normal retransmission mechanism and timeouts to
+ check the liveness of a peer, as all messages are used for liveness
+ checking. For compatibility reasons, with IKEv1 a custom interval may be
+ specified; this option has no effect on connections using IKE2.
+
+connections.<conn>.fragmentation = no
+ Use IKEv1 UDP packet fragmentation (_yes_, _no_ or _force_).
+
+ The default of _no_ disables IKEv1 fragmentation mechanism, _yes_ enables
+ it if support has been indicated by the peer. _force_ enforces
+ fragmentation if required even before the peer had a chance to indicate
+ support for it.
+
+ IKE fragmentation is currently not supported with IKEv2.
+
+connections.<conn>.send_certreq = yes
+ Send certificate requests payloads (_yes_ or _no_).
+
+ Send certificate request payloads to offer trusted root CA certificates
+ to the peer. Certificate requests help the peer to choose an appropriate
+ certificate/private key for authentication and are enabled by default.
+
+ Disabling certificate requests can be useful if too many trusted root CA
+ certificates are installed, as each certificate request increases the size
+ of the initial IKE packets.
+
+connections.<conn>.send_cert = ifasked
+ Send certificate payloads (_yes_, _no_ or _ifasked_).
+
+ Send certificate payloads when using certificate authentication. With the
+ default of _ifasked_ the daemon sends certificate payloads only if
+ certificate requests have been received. _no_ disables sending of
+ certificate payloads, _yes_ always sends certificate payloads whenever
+ certificate authentication is used.
+
+connections.<conn>.keyingtries = 1
+ Number of retransmission sequences to perform during initial connect.
+
+ Number of retransmission sequences to perform during initial connect.
+ Instead of giving up initiation after the first retransmission sequence with
+ the default value of _1_, additional sequences may be started according to
+ the configured value. A value of _0_ initiates a new sequence until the
+ connection establishes or fails with a permanent error.
+
+connections.<conn>.unique = no
+ Connection uniqueness policy (_never_, _no_, _keep_ or _replace_).
+
+ Connection uniqueness policy to enforce. To avoid multiple connections
+ from the same user, a uniqueness policy can be enforced. The value _never_
+ does never enforce such a policy, even if a peer included INITIAL_CONTACT
+ notification messages, whereas _no_ replaces existing connections for the
+ same identity if a new one has the INITIAL_CONTACT notify. _keep_ rejects
+ new connection attempts if the same user already has an active connection,
+ _replace_ deletes any existing connection if a new one for the same user
+ gets established.
+
+ To compare connections for uniqueness, the remote IKE identity is used. If
+ EAP or XAuth authentication is involved, the EAP-Identity or XAuth username
+ is used to enforce the uniqueness policy instead.
+
+connections.<conn>.reauth_time = 0s
+ Time to schedule IKE reauthentication.
+
+ Time to schedule IKE reauthentication. IKE reauthentication recreates the
+ IKE/ISAKMP SA from scratch and re-evaluates the credentials. In asymmetric
+ configurations (with EAP or configuration payloads) it might not be possible
+ to actively reauthenticate as responder. The IKEv2 reauthentication lifetime
+ negotiation can instruct the client to perform reauthentication.
+
+ Reauthentication is disabled by default. Enabling it usually may lead
+ to small connection interruptions, as strongSwan uses a break-before-make
+ policy with IKEv2 to avoid any conflicts with associated tunnel resources.
+
+connections.<conn>.rekey_time = 4h
+ Time to schedule IKE rekeying.
+
+ IKE rekeying refreshes key material using a Diffie-Hellman exchange, but
+ does not re-check associated credentials. It is supported in IKEv2 only,
+ IKEv1 performs a reauthentication procedure instead.
+
+ With the default value IKE rekeying is scheduled every 4 hours, minus the
+ configured **rand_time**.
+
+connections.<conn>.over_time = 10% of rekey_time/reauth_time
+ Hard IKE_SA lifetime if rekey/reauth does not complete, as time.
+
+ Hard IKE_SA lifetime if rekey/reauth does not complete, as time.
+ To avoid having an IKE/ISAKMP kept alive if IKE reauthentication or rekeying
+ fails perpetually, a maximum hard lifetime may be specified. If the
+ IKE_SA fails to rekey or reauthenticate within the specified time, the
+ IKE_SA gets closed.
+
+ In contrast to CHILD_SA rekeying, **over_time** is relative in time to the
+ **rekey_time** _and_ **reauth_time** values, as it applies to both.
+
+ The default is 10% of the longer of **rekey_time** and **reauth_time**.
+
+connections.<conn>.rand_time = over_time
+ Range of random time to subtract from rekey/reauth times.
+
+ Time range from which to choose a random value to subtract from
+ rekey/reauth times. To avoid having both peers initiating the rekey/reauth
+ procedure simultaneously, a random time gets subtracted from the
+ rekey/reauth times.
+
+ The default is equal to the configured **over_time**.
+
+connections.<conn>.pools =
+ Comma separated list of named IP pools.
+
+ Comma separated list of named IP pools to allocate virtual IP addresses and
+ other configuration attributes from. Each name references a pool by name
+ from either the **pools** section or an external pool.
+
+connections.<conn>.local<suffix> {}
+ Section for a local authentication round.
+
+ Section for a local authentication round. A local authentication round
+ defines the rules how authentication is performed for the local peer.
+ Multiple rounds may be defined to use IKEv2 RFC 4739 Multiple Authentication
+ or IKEv1 XAuth.
+
+ Each round is defined in a section having _local_ as prefix, and an optional
+ unique suffix. To define a single authentication round, the suffix may be
+ omitted.
+
+connections.<conn>.local<suffix>.certs =
+ Comma separated list of certificate candidates to use for authentication.
+
+ Comma separated list of certificate candidates to use for authentication.
+ The certificates may use a relative path from the **swanctl** _x509_
+ directory, or an absolute path.
+
+ The certificate used for authentication is selected based on the received
+ certificate request payloads. If no appropriate CA can be located, the
+ first certificate is used.
+
+connections.<conn>.local<suffix>.auth = pubkey
+ Authentication to perform locally (_pubkey_, _psk_, _xauth[-backend]_ or
+ _eap[-method]_).
+
+ Authentication to perform locally. _pubkey_ uses public key authentication
+ using a private key associated to a usable certificate. _psk_ uses
+ pre-shared key authentication. The IKEv1 specific _xauth_ is used for
+ XAuth or Hybrid authentication, while the IKEv2 specific _eap_ keyword
+ defines EAP authentication.
+
+ For _xauth_, a specific backend name may be appended, separated by a dash.
+ The appropriate _xauth_ backend is selected to perform the XAuth exchange.
+ For traditional XAuth, the _xauth_ method is usually defined in the second
+ authentication round following an initial _pubkey_ (or _psk_) round. Using
+ _xauth_ in the first round performs Hybrid Mode client authentication.
+
+ For _eap_, a specific EAP method name may be appended, separated by a dash.
+ An EAP module implementing the appropriate method is selected to perform
+ the EAP conversation.
+
+connections.<conn>.local<suffix>.id =
+ IKE identity to use for authentication round.
+
+ IKE identity to use for authentication round. When using certificate
+ authentication, the IKE identity must be contained in the certificate,
+ either as subject or as subjectAltName.
+
+connections.<conn>.local<suffix>.eap_id = id
+ Client EAP-Identity to use in EAP-Identity exchange and the EAP method.
+
+connections.<conn>.local<suffix>.aaa_id = remote-id
+ Server side EAP-Identity to expect in the EAP method.
+
+ Server side EAP-Identity to expect in the EAP method. Some EAP methods, such
+ as EAP-TLS, use an identity for the server to perform mutual authentication.
+ This identity may differ from the IKE identity, especially when EAP
+ authentication is delegated from the IKE responder to an AAA backend.
+
+ For EAP-(T)TLS, this defines the identity for which the server must provide
+ a certificate in the TLS exchange.
+
+connections.<conn>.local<suffix>.xauth_id = id
+ Client XAuth username used in the XAuth exchange.
+
+connections.<conn>.remote<suffix> {}
+ Section for a remote authentication round.
+
+ Section for a remote authentication round. A remote authentication round
+ defines the constraints how the peers must authenticate to use this
+ connection. Multiple rounds may be defined to use IKEv2 RFC 4739 Multiple
+ Authentication or IKEv1 XAuth.
+
+ Each round is defined in a section having _remote_ as prefix, and an
+ optional unique suffix. To define a single authentication round, the suffix
+ may be omitted.
+
+connections.<conn>.remote<suffix>.id = %any
+ IKE identity to expect for authentication round.
+
+ IKE identity to expect for authentication round. When using certificate
+ authentication, the IKE identity must be contained in the certificate,
+ either as subject or as subjectAltName.
+
+connections.<conn>.remote<suffix>.groups =
+ Authorization group memberships to require.
+
+ Comma separated authorization group memberships to require. The peer must
+ prove membership to at least one of the specified groups. Group membership
+ can be certified by different means, for example by appropriate Attribute
+ Certificates or by an AAA backend involved in the authentication.
+
+connections.<conn>.remote<suffix>.certs =
+ Comma separated list of certificate to accept for authentication.
+
+ Comma separated list of certificates to accept for authentication.
+ The certificates may use a relative path from the **swanctl** _x509_
+ directory, or an absolute path.
+
+connections.<conn>.remote<suffix>.cacert =
+ Comma separated list of CA certificates to accept for authentication.
+
+ Comma separated list of CA certificates to accept for authentication.
+ The certificates may use a relative path from the **swanctl** _x509ca_
+ directory, or an absolute path.
+
+connections.<conn>.remote<suffix>.revocation = relaxed
+ Certificate revocation policy, (_strict_, _ifuri_ or _relaxed_).
+
+ Certificate revocation policy for CRL or OCSP revocation.
+
+ A _strict_ revocation policy fails if no revocation information is
+ available, i.e. the certificate is not known to be unrevoked.
+
+ _ifuri_ fails only if a CRL/OCSP URI is available, but certificate
+ revocation checking fails, i.e. there should be revocation information
+ available, but it could not be obtained.
+
+ The default revocation policy _relaxed_ fails only if a certificate
+ is revoked, i.e. it is explicitly known that it is bad.
+
+connections.<conn>.remote<suffix>.auth = pubkey
+ Authentication to expect from remote (_pubkey_, _psk_, _xauth[-backend]_ or
+ _eap[-method]_).
+
+ Authentication to expect from remote. See the **local** sections **auth**
+ keyword description about the details of supported mechanisms.
+
+connections.<conn>.children.<child> {}
+ CHILD_SA configuration sub-section.
+
+ CHILD_SA configuration sub-section. Each connection definition may have
+ one or more sections in its _children_ subsection. The section name
+ defines the name of the CHILD_SA configuration, which must be unique within
+ the connection.
+
+connections.<conn>.children.<child>.ah_proposals =
+ AH proposals to offer for the CHILD_SA.
+
+ AH proposals to offer for the CHILD_SA. A proposal is a set of algorithms.
+ For AH, this includes an integrity algorithm and an optional Diffie-Hellman
+ group. If a DH group is specified, CHILD_SA/Quick Mode rekeying and initial
+ negotiation uses a separate Diffie-Hellman exchange using the specified
+ group.
+
+ In IKEv2, multiple algorithms of the same kind can be specified in a single
+ proposal, from which one gets selected. In IKEv1, only one algorithm per
+ kind is allowed per proposal, more algorithms get implicitly stripped. Use
+ multiple proposals to offer different algorithms combinations in IKEv1.
+
+ Algorithm keywords get separated using dashes. Multiple proposals may be
+ separated by commas. The special value _default_ forms a default proposal
+ of supported algorithms considered safe, and is usually a good choice
+ for interoperability. By default no AH proposals are included, instead ESP
+ is proposed.
+
+connections.<conn>.children.<child>.esp_proposals = default
+ ESP proposals to offer for the CHILD_SA.
+
+ ESP proposals to offer for the CHILD_SA. A proposal is a set of algorithms.
+ For ESP non-AEAD proposals, this includes an integrity algorithm, an
+ encryption algorithm, an optional Diffie-Hellman group and an optional
+ Extended Sequence Number Mode indicator. For AEAD proposals, a combined
+ mode algorithm is used instead of the separate encryption/integrity
+ algorithms.
+
+ If a DH group is specified, CHILD_SA/Quick Mode rekeying and initial (non
+ IKE_AUTH piggybacked) negotiation uses a separate Diffie-Hellman exchange
+ using the specified group. Extended Sequence Number support may be indicated
+ with the _esn_ and _noesn_ values, both may be included to indicate support
+ for both modes. If omitted, _noesn_ is assumed.
+
+ In IKEv2, multiple algorithms of the same kind can be specified in a single
+ proposal, from which one gets selected. In IKEv1, only one algorithm per
+ kind is allowed per proposal, more algorithms get implicitly stripped. Use
+ multiple proposals to offer different algorithms combinations in IKEv1.
+
+ Algorithm keywords get separated using dashes. Multiple proposals may be
+ separated by commas. The special value _default_ forms a default proposal
+ of supported algorithms considered safe, and is usually a good choice
+ for interoperability. If no algorithms are specified for AH nor ESP,
+ the _default_ set of algorithms for ESP is included.
+
+connections.<conn>.children.<child>.local_ts = dynamic
+ Local traffic selectors to include in CHILD_SA.
+
+ Comma separated list of local traffic selectors to include in CHILD_SA.
+ Each selector is a CIDR subnet definition, followed by an optional
+ proto/port selector. The special value _dynamic_ may be used instead of a
+ subnet definition, which gets replaced by the tunnel outer address or the
+ virtual IP, if negotiated. This is the default.
+
+ A protocol/port selector is surrounded by opening and closing square
+ brackets. Between these brackets, a numeric or **getservent**(3) protocol
+ name may be specified. After the optional protocol restriction, an optional
+ port restriction may be specified, separated by a slash. The port
+ restriction may be numeric, a **getservent**(3) service name, or the special
+ value _opaque_ for RFC 4301 OPAQUE selectors. Port ranges may be specified
+ as well, none of the kernel backends currently support port ranges, though.
+
+ Unless the Unity extension is used, IKEv1 supports the first specified
+ selector only. IKEv1 uses very similar traffic selector narrowing as it is
+ supported in the IKEv2 protocol.
+
+connections.<conn>.children.<child>.remote_ts = dynamic
+ Remote selectors to include in CHILD_SA.
+
+ Comma separated list of remote selectors to include in CHILD_SA. See
+ **local_ts** for a description of the selector syntax.
+
+connections.<conn>.children.<child>.rekey_time = 1h
+ Time to schedule CHILD_SA rekeying.
+
+ Time to schedule CHILD_SA rekeying. CHILD_SA rekeying refreshes key
+ material, optionally using a Diffie-Hellman exchange if a group is
+ specified in the proposal.
+
+ To avoid rekey collisions initiated by both ends simultaneously, a value
+ in the range of **rand_time** gets subtracted to form the effective soft
+ lifetime.
+
+ By default CHILD_SA rekeying is scheduled every hour, minus **rand_time**.
+
+connections.<conn>.children.<child>.life_time = rekey_time + 10%
+ Maximum lifetime before CHILD_SA gets closed, as time.
+
+ Maximum lifetime before CHILD_SA gets closed. Usually this hard lifetime
+ is never reached, because the CHILD_SA gets rekeyed before.
+ If that fails for whatever reason, this limit closes the CHILD_SA.
+
+ The default is 10% more than the **rekey_time**.
+
+connections.<conn>.children.<child>.rand_time = life_time - rekey_time
+ Range of random time to subtract from **rekey_time**.
+
+ Time range from which to choose a random value to subtract from
+ **rekey_time**. The default is the difference between **life_time** and
+ **rekey_time**.
+
+connections.<conn>.children.<child>.rekey_bytes = 0
+ Number of bytes processed before initiating CHILD_SA rekeying.
+
+ Number of bytes processed before initiating CHILD_SA rekeying. CHILD_SA
+ rekeying refreshes key material, optionally using a Diffie-Hellman exchange
+ if a group is specified in the proposal.
+
+ To avoid rekey collisions initiated by both ends simultaneously, a value
+ in the range of **rand_bytes** gets subtracted to form the effective soft
+ volume limit.
+
+ Volume based CHILD_SA rekeying is disabled by default.
+
+connections.<conn>.children.<child>.life_bytes = rekey_bytes + 10%
+ Maximum bytes processed before CHILD_SA gets closed.
+
+ Maximum bytes processed before CHILD_SA gets closed. Usually this hard
+ volume limit is never reached, because the CHILD_SA gets rekeyed before.
+ If that fails for whatever reason, this limit closes the CHILD_SA.
+
+ The default is 10% more than **rekey_bytes**.
+
+connections.<conn>.children.<child>.rand_bytes = life_bytes - rekey_bytes
+ Range of random bytes to subtract from **rekey_bytes**.
+
+ Byte range from which to choose a random value to subtract from
+ **rekey_bytes**. The default is the difference between **life_bytes** and
+ **rekey_bytes**.
+
+connections.<conn>.children.<child>.rekey_packets = 0
+ Number of packets processed before initiating CHILD_SA rekeying.
+
+ Number of packets processed before initiating CHILD_SA rekeying. CHILD_SA
+ rekeying refreshes key material, optionally using a Diffie-Hellman exchange
+ if a group is specified in the proposal.
+
+ To avoid rekey collisions initiated by both ends simultaneously, a value
+ in the range of **rand_packets** gets subtracted to form the effective soft
+ packet count limit.
+
+ Packet count based CHILD_SA rekeying is disabled by default.
+
+connections.<conn>.children.<child>.life_packets = rekey_packets + 10%
+ Maximum number of packets processed before CHILD_SA gets closed.
+
+ Maximum number of packets processed before CHILD_SA gets closed. Usually
+ this hard packets limit is never reached, because the CHILD_SA gets rekeyed
+ before. If that fails for whatever reason, this limit closes the CHILD_SA.
+
+ The default is 10% more than **rekey_bytes**.
+
+connections.<conn>.children.<child>.rand_packets = life_packets - rekey_packets
+ Range of random packets to subtract from **packets_bytes**.
+
+ Packet range from which to choose a random value to subtract from
+ **rekey_packets**. The default is the difference between **life_packets**
+ and **rekey_packets**.
+
+connections.<conn>.children.<child>.updown =
+ Updown script to invoke on CHILD_SA up and down events.
+
+connections.<conn>.children.<child>.hostaccess = yes
+ Hostaccess variable to pass to **updown** script.
+
+connections.<conn>.children.<child>.mode = tunnel
+ IPsec Mode to establish (_tunnel_, _transport_, _beet_, _pass_ or _drop_).
+
+ IPsec Mode to establish CHILD_SA with. _tunnel_ negotiates the CHILD_SA
+ in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode. _beet_
+ is the Bound End to End Tunnel mixture mode, working with fixed inner
+ addresses without the need to include them in each packet.
+
+ Both _transport_ and _beet_ modes are subject to mode negotiation; _tunnel_
+ mode is negotiated if the preferred mode is not available.
+
+ _pass_ and _drop_ are used to install shunt policies, which explicitly
+ bypass the defined traffic from IPsec processing, or drop it, respectively.
+
+connections.<conn>.children.<child>.dpd_action = clear
+ Action to perform on DPD timeout (_clear_, _trap_ or _restart_).
+
+ Action to perform for this CHILD_SA on DPD timeout. The default _clear_
+ closes the CHILD_SA and does not take further action. _trap_ installs
+ a trap policy, which will catch matching traffic and tries to re-negotiate
+ the tunnel on-demand. _restart_ immediately tries to re-negotiate the
+ CHILD_SA under a fresh IKE_SA.
+
+connections.<conn>.children.<child>.ipcomp = no
+ Enable IPComp compression before encryption.
+
+ Enable IPComp compression before encryption. If enabled, IKE tries to
+ negotiate IPComp compression to compress ESP payload data prior to
+ encryption.
+
+connections.<conn>.children.<child>.inactivity = 0s
+ Timeout before closing CHILD_SA after inactivity.
+
+ Timeout before closing CHILD_SA after inactivity. If no traffic has
+ been processed in either direction for the configured timeout, the CHILD_SA
+ gets closed due to inactivity. The default value of _0_ disables inactivity
+ checks.
+
+connections.<conn>.children.<child>.reqid = 0
+ Fixed reqid to use for this CHILD_SA.
+
+ Fixed reqid to use for this CHILD_SA. This might be helpful in some
+ scenarios, but works only if each CHILD_SA configuration is instantiated
+ not more than once. The default of _0_ uses dynamic reqids, allocated
+ incrementally.
+
+connections.<conn>.children.<child>.mark_in = 0/0x00000000
+ Netfilter mark and mask for input traffic.
+
+ Netfilter mark and mask for input traffic. On Linux Netfilter may apply
+ marks to each packet coming from a tunnel having that option set. The
+ mark may then be used by Netfilter to match rules.
+
+ An additional mask may be appended to the mark, separated by _/_. The
+ default mask if omitted is 0xffffffff.
+
+connections.<conn>.children.<child>.mark_out = 0/0x00000000
+ Netfilter mark and mask for output traffic.
+
+ Netfilter mark and mask for output traffic. On Linux Netfilter may require
+ marks on each packet to match a policy having that option set. This allows
+ Netfilter rules to select specific tunnels for outgoing traffic.
+
+ An additional mask may be appended to the mark, separated by _/_. The
+ default mask if omitted is 0xffffffff.
+
+connections.<conn>.children.<child>.tfc_padding = 0
+ Traffic Flow Confidentiality padding.
+
+ Pads ESP packets with additional data to have a consistent ESP packet size
+ for improved Traffic Flow Confidentiality. The padding defines the minimum
+ size of all ESP packets sent.
+
+ The default value of 0 disables TFC padding, the special value _mtu_ adds
+ TFC padding to create a packet size equal to the Path Maximum Transfer Unit.
+
+connections.<conn>.children.<child>.replay_window = 32
+ IPsec replay window to configure for this CHILD_SA.
+
+ IPsec replay window to configure for this CHILD_SA. Larger values than the
+ default of 32 are supported using the Netlink backend only, a value of 0
+ disables IPsec replay protection.
+
+connections.<conn>.children.<child>.start_action = none
+ Action to perform after loading the configuration (_none_, _trap_, _start_).
+
+ Action to perform after loading the configuration. The default of _none_
+ loads the connection only, which then can be manually initiated or used as
+ a responder configuration.
+
+ The value _trap_ installs a trap policy, which triggers the tunnel as soon
+ as matching traffic has been detected. The value _start_ initiates
+ the connection actively.
+
+ When unloading or replacing a CHILD_SA configuration having a
+ **start_action** different from _none_, the inverse action is performed.
+ Configurations with _start_ get closed, while such with _trap_ get
+ uninstalled.
+
+connections.<conn>.children.<child>.close_action = none
+ Action to perform after a CHILD_SA gets closed (_none_, _trap_, _start_).
+
+ Action to perform after a CHILD_SA gets closed by the peer. The default of
+ _none_ does not take any action, _trap_ installs a trap policy for the
+ CHILD_SA. _start_ tries to re-create the CHILD_SA.
+
+ **close_action** does not provide any guarantee that the CHILD_SA is kept
+ alive. It acts on explicit close messages only, but not on negotiation
+ failures. Use trap policies to reliably re-create failed CHILD_SAs.
+
+secrets { # }
+ Section defining secrets for IKE/EAP/XAuth authentication and private
+ key decryption.
+
+ Section defining secrets for IKE/EAP/XAuth authentication and private key
+ decryption. The **secrets** section takes sub-sections having a specific
+ prefix which defines the secret type.
+
+ It is not recommended to define any private key decryption passphrases,
+ as then there is no real security benefit in having encrypted keys. Either
+ store the key unencrypted, or enter the keys manually when loading
+ credentials.
+
+secrets.eap<suffix> { # }
+ EAP secret section for a specific secret.
+
+ EAP secret section for a specific secret. Each EAP secret is defined in
+ a unique section having the _eap_ prefix. EAP secrets are used for XAuth
+ authentication as well.
+
+secrets.xauth<suffix> { # }
+ XAuth secret section for a specific secret.
+
+ XAuth secret section for a specific secret. **xauth** is just an alias
+ for **eap**, secrets under both section prefixes are used for both EAP and
+ XAuth authentication.
+
+secrets.eap<suffix>.secret =
+ Value of the EAP/XAuth secret.
+
+ Value of the EAP/XAuth secret. It may either be an ASCII string, a hex
+ encoded string if it has a _0x_ prefix, or a Base64 encoded string if it
+ has a _0s_ prefix in its value.
+
+secrets.eap<suffix>.id<suffix> =
+ Identity the EAP/XAuth secret belongs to.
+
+ Identity the EAP/XAuth secret belongs to. Multiple unique identities may
+ be specified, each having an _id_ prefix, if a secret is shared between
+ multiple users.
+
+secrets.ike<suffix> { # }
+ IKE preshared secret section for a specific secret.
+
+ IKE preshared secret section for a specific secret. Each IKE PSK is defined
+ in a unique section having the _ike_ prefix.
+
+secrets.ike<suffix>.secret =
+ Value of the IKE preshared secret.
+
+ Value of the IKE preshared secret. It may either be an ASCII string,
+ a hex encoded string if it has a _0x_ prefix, or a Base64 encoded string if
+ it has a _0s_ prefix in its value.
+
+secrets.ike<suffix>.id<suffix> =
+ IKE identity the IKE preshared secret belongs to.
+
+ IKE identity the IKE preshared secret belongs to. Multiple unique identities
+ may be specified, each having an _id_ prefix, if a secret is shared between
+ multiple peers.
+
+secrets.rsa<suffix> { # }
+ Private key decryption passphrase for a key in the _rsa_ folder.
+
+secrets.rsa<suffix>.file =
+ File name in the _rsa_ folder for which this passphrase should be used.
+
+secrets.rsa<suffix>.secret
+ Value of decryption passphrase for RSA key.
+
+secrets.ecdsa<suffix> { # }
+ Private key decryption passphrase for a key in the _ecdsa_ folder.
+
+secrets.ecdsa<suffix>.file =
+ File name in the _ecdsa_ folder for which this passphrase should be used.
+
+secrets.ecdsa<suffix>.secret
+ Value of decryption passphrase for ECDSA key.
+
+secrets.pkcs8<suffix> { # }
+ Private key decryption passphrase for a key in the _pkcs8_ folder.
+
+secrets.pkcs8<suffix>.file =
+ File name in the _pkcs8_ folder for which this passphrase should be used.
+
+secrets.pkcs8<suffix>.secret
+ Value of decryption passphrase for PKCS#8 key.
+
+pools { # }
+ Section defining named pools.
+
+ Section defining named pools. Named pools may be referenced by connections
+ with the **pools** option to assign virtual IPs and other configuration
+ attributes.
+
+pools.<name> { # }
+ Section defining a single pool with a unique name.
+
+pools.<name>.addrs =
+ Subnet defining addresses allocated in pool.
+
+ Subnet defining addresses allocated in pool. Accepts a single CIDR subnet
+ defining the pool to allocate addresses from. Pools must be unique and
+ non-overlapping.
+
+pools.<name>.<attr> =
+ Comma separated list of additional attributes from type <attr>.
+
+ Comma separated list of additional attributes of type **<attr>**. The
+ attribute type may be one of _dns_, _nbns_, _dhcp_, _netmask_, _server_,
+ _subnet_, _split_include_ and _split_exclude_ to define addresses or CIDR
+ subnets for the corresponding attribute types. Alternatively, **<attr>** can
+ be a numerical identifier, for which string attribute values are accepted
+ as well.