From 81c63b0eed39432878f78727f60a1e7499645199 Mon Sep 17 00:00:00 2001 From: Yves-Alexis Perez Date: Fri, 11 Jul 2014 07:23:31 +0200 Subject: Imported Upstream version 5.2.0 --- src/swanctl/Makefile.am | 66 +++ src/swanctl/Makefile.in | 981 +++++++++++++++++++++++++++++++++++++ src/swanctl/command.c | 309 ++++++++++++ src/swanctl/command.h | 108 ++++ src/swanctl/commands/initiate.c | 132 +++++ src/swanctl/commands/install.c | 125 +++++ src/swanctl/commands/list_certs.c | 670 +++++++++++++++++++++++++ src/swanctl/commands/list_conns.c | 242 +++++++++ src/swanctl/commands/list_pols.c | 210 ++++++++ src/swanctl/commands/list_pools.c | 101 ++++ src/swanctl/commands/list_sas.c | 366 ++++++++++++++ src/swanctl/commands/load_conns.c | 419 ++++++++++++++++ src/swanctl/commands/load_creds.c | 574 ++++++++++++++++++++++ src/swanctl/commands/load_pools.c | 292 +++++++++++ src/swanctl/commands/log.c | 101 ++++ src/swanctl/commands/stats.c | 118 +++++ src/swanctl/commands/terminate.c | 157 ++++++ src/swanctl/commands/version.c | 96 ++++ src/swanctl/swanctl.8.in | 83 ++++ src/swanctl/swanctl.c | 57 +++ src/swanctl/swanctl.conf | 306 ++++++++++++ src/swanctl/swanctl.conf.5.head.in | 24 + src/swanctl/swanctl.conf.5.main | 957 ++++++++++++++++++++++++++++++++++++ src/swanctl/swanctl.conf.5.tail.in | 10 + src/swanctl/swanctl.h | 69 +++ src/swanctl/swanctl.opt | 779 +++++++++++++++++++++++++++++ 26 files changed, 7352 insertions(+) create mode 100644 src/swanctl/Makefile.am create mode 100644 src/swanctl/Makefile.in create mode 100644 src/swanctl/command.c create mode 100644 src/swanctl/command.h create mode 100644 src/swanctl/commands/initiate.c create mode 100644 src/swanctl/commands/install.c create mode 100644 src/swanctl/commands/list_certs.c create mode 100644 src/swanctl/commands/list_conns.c create mode 100644 src/swanctl/commands/list_pols.c create mode 100644 src/swanctl/commands/list_pools.c create mode 100644 src/swanctl/commands/list_sas.c create mode 100644 src/swanctl/commands/load_conns.c create mode 100644 src/swanctl/commands/load_creds.c create mode 100644 src/swanctl/commands/load_pools.c create mode 100644 src/swanctl/commands/log.c create mode 100644 src/swanctl/commands/stats.c create mode 100644 src/swanctl/commands/terminate.c create mode 100644 src/swanctl/commands/version.c create mode 100644 src/swanctl/swanctl.8.in create mode 100644 src/swanctl/swanctl.c create mode 100644 src/swanctl/swanctl.conf create mode 100644 src/swanctl/swanctl.conf.5.head.in create mode 100644 src/swanctl/swanctl.conf.5.main create mode 100644 src/swanctl/swanctl.conf.5.tail.in create mode 100644 src/swanctl/swanctl.h create mode 100644 src/swanctl/swanctl.opt (limited to 'src/swanctl') 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 . + * + * 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 +#include +#include +#include +#include + +#include +#include +#include + +/** + * 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 . + * + * 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 +#include + +/** + * 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 . + * + * 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 + +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 [--timeout ] [--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 . + * + * 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 + +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 [--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 [--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 . + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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, ¬Before, ¬After); + printf("validity: not before %T, ", ¬Before, FALSE); + if (now < notBefore) + { + printf("not valid yet (valid in %V)\n", &now, ¬Before); + } + else + { + printf("ok\n"); + } + printf(" not after %T, ", ¬After, FALSE); + if (now > notAfter) + { + printf("expired (%V ago)\n", &now, ¬After); + } + else + { + printf("ok (expires in %V)\n", &now, ¬After); + } + + 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 ] [--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 . + * + * 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 +#include + +#include "command.h" + +#include + +/** + * 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 . + * + * 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 +#include + +#include "command.h" + +#include + +/** + * 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 ] [--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 . + * + * 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 +#include + +#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 . + * + * 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 +#include + +#include "command.h" + +#include + +/** + * 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 . + * + * 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 +#include +#include + +#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, ¤t)) + { + 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, §ion)) + { + 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**)§ion) == 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 . + * + * 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 +#include +#include +#include + +#include "command.h" +#include "swanctl.h" + +#include +#include + +/** + * 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, §ion)) + { + 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, §ion)) + { + 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 . + * + * 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 +#include +#include + +#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, ¤t)) + { + 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, §ion)) + { + 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**)§ion) == 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 . + * + * 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 +#include + +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 . + * + * 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 + +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 . + * + * 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 + +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 | --ike | --ike-id ", + "[--timeout ] [--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 . + * + * 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 + +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 . + * + * 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 + +#include + +/** + * 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 . + # { + + # 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 { + + # 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 { + + # 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. + # { + + # 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 { + + # Value of the EAP/XAuth secret. + # secret = + + # Identity the EAP/XAuth secret belongs to. + # id = + + # } + + # XAuth secret section for a specific secret. + # xauth { + + # } + + # IKE preshared secret section for a specific secret. + # ike { + + # Value of the IKE preshared secret. + # secret = + + # IKE identity the IKE preshared secret belongs to. + # id = + + # } + + # Private key decryption passphrase for a key in the rsa folder. + # rsa { + + # 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 { + + # 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 { + + # 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. + # { + + # Subnet defining addresses allocated in pool. + # addrs = + + # Comma separated list of additional attributes from type . + # = + + # } + +# } + 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 "" "" "," +but an arbitrary yet unique connection name can be chosen for each connection +subsection. + +.TP +.B connections. +.br +Section for an IKE connection named . + +.TP +.BR connections..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..local +.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..local.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..local.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..local.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..local.eap_id " [id]" +Client EAP\-Identity to use in EAP\-Identity exchange and the EAP method. + +.TP +.BR connections..local.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..local.xauth_id " [id]" +Client XAuth username used in the XAuth exchange. + +.TP +.B connections..remote +.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..remote.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..remote.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..remote.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..remote.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..remote.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..remote.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..children. +.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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..updown " []" +Updown script to invoke on CHILD_SA up and down events. + +.TP +.BR connections..children..hostaccess " [yes]" +Hostaccess variable to pass to +.RB "" "updown" "" +script. + +.TP +.BR connections..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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 +.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.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.id " []" +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 +.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 +.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.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.id " []" +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 +.br +Private key decryption passphrase for a key in the +.RI "" "rsa" "" +folder. + +.TP +.BR secrets.rsa.file " []" +File name in the +.RI "" "rsa" "" +folder for which this passphrase should be used. + +.TP +.BR secrets.rsa.secret " []" +Value of decryption passphrase for RSA key. + +.TP +.B secrets.ecdsa +.br +Private key decryption passphrase for a key in the +.RI "" "ecdsa" "" +folder. + +.TP +.BR secrets.ecdsa.file " []" +File name in the +.RI "" "ecdsa" "" +folder for which this passphrase should be used. + +.TP +.BR secrets.ecdsa.secret " []" +Value of decryption passphrase for ECDSA key. + +.TP +.B secrets.pkcs8 +.br +Private key decryption passphrase for a key in the +.RI "" "pkcs8" "" +folder. + +.TP +.BR secrets.pkcs8.file " []" +File name in the +.RI "" "pkcs8" "" +folder for which this passphrase should be used. + +.TP +.BR secrets.pkcs8.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. +.br +Section defining a single pool with a unique name. + +.TP +.BR pools..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.. " []" +Comma separated list of additional attributes of type +.RB "" "" "." +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 "" "" "" +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 . + * + * 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 __, but an arbitrary yet unique connection name can be + chosen for each connection subsection. + +connections. { # } + Section for an IKE connection named . + +connections..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..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..local {} + 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..local.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..local.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..local.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..local.eap_id = id + Client EAP-Identity to use in EAP-Identity exchange and the EAP method. + +connections..local.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..local.xauth_id = id + Client XAuth username used in the XAuth exchange. + +connections..remote {} + 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..remote.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..remote.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..remote.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..remote.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..remote.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..remote.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..children. {} + 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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..updown = + Updown script to invoke on CHILD_SA up and down events. + +connections..children..hostaccess = yes + Hostaccess variable to pass to **updown** script. + +connections..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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..children..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 { # } + 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 { # } + 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.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.id = + 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 { # } + 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.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.id = + 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 { # } + Private key decryption passphrase for a key in the _rsa_ folder. + +secrets.rsa.file = + File name in the _rsa_ folder for which this passphrase should be used. + +secrets.rsa.secret + Value of decryption passphrase for RSA key. + +secrets.ecdsa { # } + Private key decryption passphrase for a key in the _ecdsa_ folder. + +secrets.ecdsa.file = + File name in the _ecdsa_ folder for which this passphrase should be used. + +secrets.ecdsa.secret + Value of decryption passphrase for ECDSA key. + +secrets.pkcs8 { # } + Private key decryption passphrase for a key in the _pkcs8_ folder. + +secrets.pkcs8.file = + File name in the _pkcs8_ folder for which this passphrase should be used. + +secrets.pkcs8.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. { # } + Section defining a single pool with a unique name. + +pools..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.. = + Comma separated list of additional attributes from type . + + Comma separated list of additional attributes of type ****. 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, **** can + be a numerical identifier, for which string attribute values are accepted + as well. -- cgit v1.2.3