diff options
Diffstat (limited to 'src/libcharon/plugins')
195 files changed, 20234 insertions, 306 deletions
diff --git a/src/libcharon/plugins/addrblock/Makefile.am b/src/libcharon/plugins/addrblock/Makefile.am index 407f22d71..33ee60d86 100644 --- a/src/libcharon/plugins/addrblock/Makefile.am +++ b/src/libcharon/plugins/addrblock/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-addrblock.la diff --git a/src/libcharon/plugins/addrblock/Makefile.in b/src/libcharon/plugins/addrblock/Makefile.in index 0aa635a43..0655959ca 100644 --- a/src/libcharon/plugins/addrblock/Makefile.in +++ b/src/libcharon/plugins/addrblock/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-addrblock.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-addrblock.la diff --git a/src/libcharon/plugins/android_dns/Makefile.am b/src/libcharon/plugins/android_dns/Makefile.am index ebad963bb..1a0d6e6f2 100644 --- a/src/libcharon/plugins/android_dns/Makefile.am +++ b/src/libcharon/plugins/android_dns/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-android-dns.la diff --git a/src/libcharon/plugins/android_dns/Makefile.in b/src/libcharon/plugins/android_dns/Makefile.in index f44734cc6..287c94acc 100644 --- a/src/libcharon/plugins/android_dns/Makefile.in +++ b/src/libcharon/plugins/android_dns/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-android-dns.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-android-dns.la diff --git a/src/libcharon/plugins/android_log/Makefile.am b/src/libcharon/plugins/android_log/Makefile.am index 4d8b4850b..79c61b51e 100644 --- a/src/libcharon/plugins/android_log/Makefile.am +++ b/src/libcharon/plugins/android_log/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-android-log.la diff --git a/src/libcharon/plugins/android_log/Makefile.in b/src/libcharon/plugins/android_log/Makefile.in index 361b36187..9fd515073 100644 --- a/src/libcharon/plugins/android_log/Makefile.in +++ b/src/libcharon/plugins/android_log/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-android-log.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-android-log.la diff --git a/src/libcharon/plugins/certexpire/Makefile.am b/src/libcharon/plugins/certexpire/Makefile.am index 2bfad9497..b8c241dfb 100644 --- a/src/libcharon/plugins/certexpire/Makefile.am +++ b/src/libcharon/plugins/certexpire/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-certexpire.la diff --git a/src/libcharon/plugins/certexpire/Makefile.in b/src/libcharon/plugins/certexpire/Makefile.in index e218c8a4f..edda93e77 100644 --- a/src/libcharon/plugins/certexpire/Makefile.in +++ b/src/libcharon/plugins/certexpire/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -419,7 +423,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-certexpire.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-certexpire.la diff --git a/src/libcharon/plugins/coupling/Makefile.am b/src/libcharon/plugins/coupling/Makefile.am index cbc06a6b7..badc7b7b2 100644 --- a/src/libcharon/plugins/coupling/Makefile.am +++ b/src/libcharon/plugins/coupling/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-coupling.la diff --git a/src/libcharon/plugins/coupling/Makefile.in b/src/libcharon/plugins/coupling/Makefile.in index bb951264f..5670f4323 100644 --- a/src/libcharon/plugins/coupling/Makefile.in +++ b/src/libcharon/plugins/coupling/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-coupling.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-coupling.la diff --git a/src/libcharon/plugins/coupling/coupling_validator.c b/src/libcharon/plugins/coupling/coupling_validator.c index fc35462e3..0686e0f31 100644 --- a/src/libcharon/plugins/coupling/coupling_validator.c +++ b/src/libcharon/plugins/coupling/coupling_validator.c @@ -202,6 +202,7 @@ METHOD(coupling_validator_t, destroy, void, coupling_validator_t *coupling_validator_create() { private_coupling_validator_t *this; + hash_algorithm_t alg; char *path, *hash; INIT(this, @@ -219,8 +220,13 @@ coupling_validator_t *coupling_validator_create() hash = lib->settings->get_str(lib->settings, "%s.plugins.coupling.hash", "sha1", lib->ns); - this->hasher = lib->crypto->create_hasher(lib->crypto, - enum_from_name(hash_algorithm_short_names, hash)); + if (!enum_from_name(hash_algorithm_short_names, hash, &alg)) + { + DBG1(DBG_CFG, "unknown coupling hash algorithm: %s", hash); + destroy(this); + return NULL; + } + this->hasher = lib->crypto->create_hasher(lib->crypto, alg); if (!this->hasher) { DBG1(DBG_CFG, "unsupported coupling hash algorithm: %s", hash); diff --git a/src/libcharon/plugins/dhcp/Makefile.am b/src/libcharon/plugins/dhcp/Makefile.am index e0e857eed..3c09db016 100644 --- a/src/libcharon/plugins/dhcp/Makefile.am +++ b/src/libcharon/plugins/dhcp/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-dhcp.la diff --git a/src/libcharon/plugins/dhcp/Makefile.in b/src/libcharon/plugins/dhcp/Makefile.in index 81f2b7868..da364b06e 100644 --- a/src/libcharon/plugins/dhcp/Makefile.in +++ b/src/libcharon/plugins/dhcp/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -264,6 +264,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -282,6 +283,7 @@ 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@ @@ -309,6 +311,7 @@ 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@ @@ -400,6 +403,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -416,7 +420,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-dhcp.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-dhcp.la diff --git a/src/libcharon/plugins/dnscert/Makefile.am b/src/libcharon/plugins/dnscert/Makefile.am index 51d542b30..145562522 100644 --- a/src/libcharon/plugins/dnscert/Makefile.am +++ b/src/libcharon/plugins/dnscert/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-dnscert.la diff --git a/src/libcharon/plugins/dnscert/Makefile.in b/src/libcharon/plugins/dnscert/Makefile.in index d9eeddf70..d408cd24e 100644 --- a/src/libcharon/plugins/dnscert/Makefile.in +++ b/src/libcharon/plugins/dnscert/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-dnscert.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-dnscert.la diff --git a/src/libcharon/plugins/duplicheck/Makefile.am b/src/libcharon/plugins/duplicheck/Makefile.am index 4ea2becf3..338a114fe 100644 --- a/src/libcharon/plugins/duplicheck/Makefile.am +++ b/src/libcharon/plugins/duplicheck/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-duplicheck.la diff --git a/src/libcharon/plugins/duplicheck/Makefile.in b/src/libcharon/plugins/duplicheck/Makefile.in index 0b12cf320..97432f1b1 100644 --- a/src/libcharon/plugins/duplicheck/Makefile.in +++ b/src/libcharon/plugins/duplicheck/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -273,6 +273,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -291,6 +292,7 @@ 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@ @@ -318,6 +320,7 @@ 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@ @@ -409,6 +412,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -426,7 +430,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-duplicheck.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-duplicheck.la diff --git a/src/libcharon/plugins/eap_aka/Makefile.am b/src/libcharon/plugins/eap_aka/Makefile.am index ba6e66039..75e8eafb2 100644 --- a/src/libcharon/plugins/eap_aka/Makefile.am +++ b/src/libcharon/plugins/eap_aka/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-aka.la diff --git a/src/libcharon/plugins/eap_aka/Makefile.in b/src/libcharon/plugins/eap_aka/Makefile.in index 9e771ae46..5b20fe5a6 100644 --- a/src/libcharon/plugins/eap_aka/Makefile.in +++ b/src/libcharon/plugins/eap_aka/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -267,6 +267,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -285,6 +286,7 @@ 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@ @@ -312,6 +314,7 @@ 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@ @@ -403,6 +406,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -420,7 +424,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-aka.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-aka.la diff --git a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.am b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.am index 4e2b207d2..ec145a39e 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.am +++ b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) libstrongswan_eap_aka_3gpp2_la_LDFLAGS = -module -avoid-version libstrongswan_eap_aka_3gpp2_la_LIBADD = -lgmp diff --git a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in index 91c4bb10b..d0ee19899 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in +++ b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -268,6 +268,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -286,6 +287,7 @@ 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@ @@ -313,6 +315,7 @@ 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@ @@ -404,6 +407,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -421,7 +425,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) libstrongswan_eap_aka_3gpp2_la_LDFLAGS = -module -avoid-version libstrongswan_eap_aka_3gpp2_la_LIBADD = -lgmp $(am__append_1) diff --git a/src/libcharon/plugins/eap_dynamic/Makefile.am b/src/libcharon/plugins/eap_dynamic/Makefile.am index 13b4d10b1..58b827a78 100644 --- a/src/libcharon/plugins/eap_dynamic/Makefile.am +++ b/src/libcharon/plugins/eap_dynamic/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-dynamic.la diff --git a/src/libcharon/plugins/eap_dynamic/Makefile.in b/src/libcharon/plugins/eap_dynamic/Makefile.in index 16d0b4203..78b66ac96 100644 --- a/src/libcharon/plugins/eap_dynamic/Makefile.in +++ b/src/libcharon/plugins/eap_dynamic/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-dynamic.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-dynamic.la diff --git a/src/libcharon/plugins/eap_gtc/Makefile.am b/src/libcharon/plugins/eap_gtc/Makefile.am index 811366a94..c3a12ba3e 100644 --- a/src/libcharon/plugins/eap_gtc/Makefile.am +++ b/src/libcharon/plugins/eap_gtc/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-gtc.la diff --git a/src/libcharon/plugins/eap_gtc/Makefile.in b/src/libcharon/plugins/eap_gtc/Makefile.in index 1c8d51b94..7f18792c4 100644 --- a/src/libcharon/plugins/eap_gtc/Makefile.in +++ b/src/libcharon/plugins/eap_gtc/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -265,6 +265,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -283,6 +284,7 @@ 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@ @@ -310,6 +312,7 @@ 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@ @@ -401,6 +404,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -417,7 +421,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-gtc.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-gtc.la diff --git a/src/libcharon/plugins/eap_gtc/eap_gtc.c b/src/libcharon/plugins/eap_gtc/eap_gtc.c index e751b51b6..5fcd9ebc9 100644 --- a/src/libcharon/plugins/eap_gtc/eap_gtc.c +++ b/src/libcharon/plugins/eap_gtc/eap_gtc.c @@ -161,11 +161,11 @@ METHOD(eap_method_t, process_server, status_t, { /* assume that "out" contains username/password attributes */ co->destroy(co); - ci = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + ci = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY); ci->add_attribute(ci, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, user)); ci->add_attribute(ci, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, pass)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_PASSWORD, pass)); switch (xauth->process(xauth, ci, &co)) { case SUCCESS: diff --git a/src/libcharon/plugins/eap_identity/Makefile.am b/src/libcharon/plugins/eap_identity/Makefile.am index 1c155866d..6c5b43f00 100644 --- a/src/libcharon/plugins/eap_identity/Makefile.am +++ b/src/libcharon/plugins/eap_identity/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-identity.la diff --git a/src/libcharon/plugins/eap_identity/Makefile.in b/src/libcharon/plugins/eap_identity/Makefile.in index 4c536b2a0..5275a348c 100644 --- a/src/libcharon/plugins/eap_identity/Makefile.in +++ b/src/libcharon/plugins/eap_identity/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-identity.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-identity.la diff --git a/src/libcharon/plugins/eap_md5/Makefile.am b/src/libcharon/plugins/eap_md5/Makefile.am index 583598342..16aa1919b 100644 --- a/src/libcharon/plugins/eap_md5/Makefile.am +++ b/src/libcharon/plugins/eap_md5/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-md5.la diff --git a/src/libcharon/plugins/eap_md5/Makefile.in b/src/libcharon/plugins/eap_md5/Makefile.in index d9938dd00..5dd623d6e 100644 --- a/src/libcharon/plugins/eap_md5/Makefile.in +++ b/src/libcharon/plugins/eap_md5/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -265,6 +265,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -283,6 +284,7 @@ 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@ @@ -310,6 +312,7 @@ 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@ @@ -401,6 +404,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -417,7 +421,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-md5.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-md5.la diff --git a/src/libcharon/plugins/eap_mschapv2/Makefile.am b/src/libcharon/plugins/eap_mschapv2/Makefile.am index 030682d3e..4276a082d 100644 --- a/src/libcharon/plugins/eap_mschapv2/Makefile.am +++ b/src/libcharon/plugins/eap_mschapv2/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-mschapv2.la diff --git a/src/libcharon/plugins/eap_mschapv2/Makefile.in b/src/libcharon/plugins/eap_mschapv2/Makefile.in index 7caac9c76..c0e42198c 100644 --- a/src/libcharon/plugins/eap_mschapv2/Makefile.in +++ b/src/libcharon/plugins/eap_mschapv2/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-mschapv2.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-mschapv2.la diff --git a/src/libcharon/plugins/eap_peap/Makefile.am b/src/libcharon/plugins/eap_peap/Makefile.am index 19410a408..8960b84bd 100644 --- a/src/libcharon/plugins/eap_peap/Makefile.am +++ b/src/libcharon/plugins/eap_peap/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libtls AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-peap.la diff --git a/src/libcharon/plugins/eap_peap/Makefile.in b/src/libcharon/plugins/eap_peap/Makefile.in index 29d8c8bb0..615a916c1 100644 --- a/src/libcharon/plugins/eap_peap/Makefile.in +++ b/src/libcharon/plugins/eap_peap/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -267,6 +267,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -285,6 +286,7 @@ 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@ @@ -312,6 +314,7 @@ 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@ @@ -403,6 +406,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -420,7 +424,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libtls AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-peap.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-peap.la diff --git a/src/libcharon/plugins/eap_peap/eap_peap_avp.c b/src/libcharon/plugins/eap_peap/eap_peap_avp.c index f7f634a53..3f541ba23 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_avp.c +++ b/src/libcharon/plugins/eap_peap/eap_peap_avp.c @@ -25,8 +25,6 @@ static const chunk_t MS_AVP_Success = chunk_from_chars( 0x80, 0x03, 0x00, 0x02, 0x00, 0x01); static const chunk_t MS_AVP_Failure = chunk_from_chars( 0x80, 0x03, 0x00, 0x02, 0x00, 0x02); -static const chunk_t MS_SoH_Request = chunk_from_chars( - 0x00, 0x01, 0x37, 0x00, 0x00, 0x00, 0x21, 0x00, 0x02, 0x00, 0x00); typedef struct private_eap_peap_avp_t private_eap_peap_avp_t; @@ -64,19 +62,6 @@ METHOD(eap_peap_avp_t, build, void, writer->write_uint8(writer, EAP_MSTLV); avp_data = (pkt->code == EAP_SUCCESS) ? MS_AVP_Success : MS_AVP_Failure; } - /** - * Still trying to form a correct MS SoH Request - * - else if (pkt->type == EAP_MSCHAPV2) - { - code = (this->is_server) ? EAP_REQUEST : EAP_RESPONSE; - writer->write_uint8(writer, code); - writer->write_uint8(writer, pkt->identifier); - writer->write_uint16(writer, 16); - writer->write_uint8(writer, EAP_EXPANDED); - avp_data = MS_SoH_Request; - } - */ else { avp_data = chunk_skip(data, 4); diff --git a/src/libcharon/plugins/eap_radius/Makefile.am b/src/libcharon/plugins/eap_radius/Makefile.am index 6fdb0d099..bc7a7765d 100644 --- a/src/libcharon/plugins/eap_radius/Makefile.am +++ b/src/libcharon/plugins/eap_radius/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libradius AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-radius.la diff --git a/src/libcharon/plugins/eap_radius/Makefile.in b/src/libcharon/plugins/eap_radius/Makefile.in index fbce3127f..cd4355dfa 100644 --- a/src/libcharon/plugins/eap_radius/Makefile.in +++ b/src/libcharon/plugins/eap_radius/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -268,6 +268,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -286,6 +287,7 @@ 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@ @@ -313,6 +315,7 @@ 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@ @@ -404,6 +407,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -421,7 +425,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libradius AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-radius.la @MONOLITHIC_FALSE@libstrongswan_eap_radius_la_LIBADD = $(top_builddir)/src/libradius/libradius.la diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c index 5fb1bbb75..0020c5d57 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c @@ -210,7 +210,7 @@ static void add_ike_sa_parameters(private_eap_radius_accounting_t *this, { enumerator_t *enumerator; host_t *vip, *host; - char buf[128]; + char buf[MAX_RADIUS_ATTRIBUTE_SIZE + 1]; chunk_t data; u_int32_t value; diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.c b/src/libcharon/plugins/eap_radius/eap_radius_forward.c index 54d52a98c..52ea84070 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_forward.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.c @@ -232,8 +232,8 @@ static void ike2queue(message_t *message, linked_list_t *queue, enumerator = message->create_payload_enumerator(message); while (enumerator->enumerate(enumerator, &payload)) { - if (payload->get_type(payload) == NOTIFY || - payload->get_type(payload) == NOTIFY_V1) + if (payload->get_type(payload) == PLV2_NOTIFY || + payload->get_type(payload) == PLV1_NOTIFY) { notify = (notify_payload_t*)payload; if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE) @@ -362,8 +362,7 @@ static linked_list_t* parse_selector(char *selector) vendor = atoi(token); token = pos; } - type = enum_from_name(radius_attribute_type_names, token); - if (type == -1) + if (!enum_from_name(radius_attribute_type_names, token, &type)) { type = atoi(token); } diff --git a/src/libcharon/plugins/eap_radius/eap_radius_xauth.c b/src/libcharon/plugins/eap_radius/eap_radius_xauth.c index d00f6bb2c..0fea50919 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_xauth.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_xauth.c @@ -87,12 +87,12 @@ static bool build_round(private_eap_radius_xauth_t *this, cp_payload_t *cp) return FALSE; } cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, this->round.type, chunk_empty)); + PLV1_CONFIGURATION_ATTRIBUTE, this->round.type, chunk_empty)); if (this->round.message && strlen(this->round.message)) { cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_MESSAGE, + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_MESSAGE, chunk_from_str(this->round.message))); } return TRUE; @@ -103,10 +103,10 @@ METHOD(xauth_method_t, initiate, status_t, { cp_payload_t *cp; - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST); /* first message always comes with username */ cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, chunk_empty)); if (build_round(this, cp)) { @@ -211,7 +211,7 @@ METHOD(xauth_method_t, process, status_t, { return verify_radius(this); } - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST); if (build_round(this, cp)) { *out = cp; diff --git a/src/libcharon/plugins/eap_sim/Makefile.am b/src/libcharon/plugins/eap_sim/Makefile.am index 2e9dad1b8..f68138579 100644 --- a/src/libcharon/plugins/eap_sim/Makefile.am +++ b/src/libcharon/plugins/eap_sim/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-sim.la diff --git a/src/libcharon/plugins/eap_sim/Makefile.in b/src/libcharon/plugins/eap_sim/Makefile.in index 10b881f59..494efd99a 100644 --- a/src/libcharon/plugins/eap_sim/Makefile.in +++ b/src/libcharon/plugins/eap_sim/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -267,6 +267,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -285,6 +286,7 @@ 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@ @@ -312,6 +314,7 @@ 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@ @@ -403,6 +406,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -420,7 +424,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-sim.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-sim.la diff --git a/src/libcharon/plugins/eap_sim_file/Makefile.am b/src/libcharon/plugins/eap_sim_file/Makefile.am index 0d4da07d5..c38e55e2c 100644 --- a/src/libcharon/plugins/eap_sim_file/Makefile.am +++ b/src/libcharon/plugins/eap_sim_file/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ -DIPSEC_CONFDIR=\"${sysconfdir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-sim-file.la diff --git a/src/libcharon/plugins/eap_sim_file/Makefile.in b/src/libcharon/plugins/eap_sim_file/Makefile.in index e4552d196..82e7561f8 100644 --- a/src/libcharon/plugins/eap_sim_file/Makefile.in +++ b/src/libcharon/plugins/eap_sim_file/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -268,6 +268,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -286,6 +287,7 @@ 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@ @@ -313,6 +315,7 @@ 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@ @@ -404,6 +407,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -422,7 +426,7 @@ AM_CPPFLAGS = \ -DIPSEC_CONFDIR=\"${sysconfdir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-sim-file.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-sim-file.la diff --git a/src/libcharon/plugins/eap_sim_pcsc/Makefile.am b/src/libcharon/plugins/eap_sim_pcsc/Makefile.am index e5e9d01ca..22922049d 100644 --- a/src/libcharon/plugins/eap_sim_pcsc/Makefile.am +++ b/src/libcharon/plugins/eap_sim_pcsc/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ ${pcsclite_CFLAGS} \ - -rdynamic + $(PLUGIN_CFLAGS) libstrongswan_eap_sim_pcsc_la_LDFLAGS = -module -avoid-version libstrongswan_eap_sim_pcsc_la_LIBADD = ${pcsclite_LIBS} diff --git a/src/libcharon/plugins/eap_sim_pcsc/Makefile.in b/src/libcharon/plugins/eap_sim_pcsc/Makefile.in index 628f5372a..9a7a1909e 100644 --- a/src/libcharon/plugins/eap_sim_pcsc/Makefile.in +++ b/src/libcharon/plugins/eap_sim_pcsc/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -269,6 +269,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -287,6 +288,7 @@ 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@ @@ -314,6 +316,7 @@ 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@ @@ -405,6 +408,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -423,7 +427,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ ${pcsclite_CFLAGS} \ - -rdynamic + $(PLUGIN_CFLAGS) libstrongswan_eap_sim_pcsc_la_LDFLAGS = -module -avoid-version libstrongswan_eap_sim_pcsc_la_LIBADD = ${pcsclite_LIBS} \ diff --git a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.am b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.am index 0f21c6849..f40efbd6f 100644 --- a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.am +++ b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-simaka-pseudonym.la diff --git a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in index 4a8127fc1..886b0c575 100644 --- a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -269,6 +269,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -287,6 +288,7 @@ 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@ @@ -314,6 +316,7 @@ 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@ @@ -405,6 +408,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -422,7 +426,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-simaka-pseudonym.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-simaka-pseudonym.la diff --git a/src/libcharon/plugins/eap_simaka_reauth/Makefile.am b/src/libcharon/plugins/eap_simaka_reauth/Makefile.am index be000c6d5..0fb622220 100644 --- a/src/libcharon/plugins/eap_simaka_reauth/Makefile.am +++ b/src/libcharon/plugins/eap_simaka_reauth/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-simaka-reauth.la diff --git a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in index 8ac480d48..57c64246b 100644 --- a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -268,6 +268,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -286,6 +287,7 @@ 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@ @@ -313,6 +315,7 @@ 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@ @@ -404,6 +407,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -421,7 +425,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libsimaka AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-simaka-reauth.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-simaka-reauth.la diff --git a/src/libcharon/plugins/eap_simaka_sql/Makefile.am b/src/libcharon/plugins/eap_simaka_sql/Makefile.am index 9a52bd8ab..b7d6fd43e 100644 --- a/src/libcharon/plugins/eap_simaka_sql/Makefile.am +++ b/src/libcharon/plugins/eap_simaka_sql/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ -DIPSEC_CONFDIR=\"${sysconfdir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-simaka-sql.la diff --git a/src/libcharon/plugins/eap_simaka_sql/Makefile.in b/src/libcharon/plugins/eap_simaka_sql/Makefile.in index 79b45a9c1..eb4d3fa95 100644 --- a/src/libcharon/plugins/eap_simaka_sql/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_sql/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -267,6 +267,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -285,6 +286,7 @@ 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@ @@ -312,6 +314,7 @@ 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@ @@ -403,6 +406,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -421,7 +425,7 @@ AM_CPPFLAGS = \ -DIPSEC_CONFDIR=\"${sysconfdir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-simaka-sql.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-simaka-sql.la diff --git a/src/libcharon/plugins/eap_tls/Makefile.am b/src/libcharon/plugins/eap_tls/Makefile.am index c4944fca1..825beb841 100644 --- a/src/libcharon/plugins/eap_tls/Makefile.am +++ b/src/libcharon/plugins/eap_tls/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libtls AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-tls.la diff --git a/src/libcharon/plugins/eap_tls/Makefile.in b/src/libcharon/plugins/eap_tls/Makefile.in index c2b8b4feb..c63d56b53 100644 --- a/src/libcharon/plugins/eap_tls/Makefile.in +++ b/src/libcharon/plugins/eap_tls/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -419,7 +423,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libtls AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-tls.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-tls.la diff --git a/src/libcharon/plugins/eap_tnc/Makefile.am b/src/libcharon/plugins/eap_tnc/Makefile.am index 9586bef14..6fc78bc9a 100644 --- a/src/libcharon/plugins/eap_tnc/Makefile.am +++ b/src/libcharon/plugins/eap_tnc/Makefile.am @@ -7,7 +7,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libtnccs AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-tnc.la diff --git a/src/libcharon/plugins/eap_tnc/Makefile.in b/src/libcharon/plugins/eap_tnc/Makefile.in index 1f2ace21d..97552dfd0 100644 --- a/src/libcharon/plugins/eap_tnc/Makefile.in +++ b/src/libcharon/plugins/eap_tnc/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -267,6 +267,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -285,6 +286,7 @@ 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@ @@ -312,6 +314,7 @@ 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@ @@ -403,6 +406,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -422,7 +426,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libtnccs AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-tnc.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-tnc.la diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.c b/src/libcharon/plugins/eap_tnc/eap_tnc.c index 2147c0482..62d23d064 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc.c +++ b/src/libcharon/plugins/eap_tnc/eap_tnc.c @@ -47,6 +47,11 @@ struct private_eap_tnc_t { eap_tnc_t public; /** + * Inner EAP authentication type + */ + eap_type_t type; + + /** * Outer EAP authentication type */ eap_type_t auth_type; @@ -124,7 +129,7 @@ METHOD(eap_method_t, initiate, status_t, private_eap_tnc_t *this, eap_payload_t **out) { chunk_t data; - u_int32_t auth_type; + uint32_t auth_type; /* Determine TNC Client Authentication Type */ switch (this->auth_type) @@ -175,10 +180,10 @@ METHOD(eap_method_t, process, status_t, } METHOD(eap_method_t, get_type, eap_type_t, - private_eap_tnc_t *this, u_int32_t *vendor) + private_eap_tnc_t *this, uint32_t *vendor) { *vendor = 0; - return EAP_TNC; + return this->type; } METHOD(eap_method_t, get_msk, status_t, @@ -192,14 +197,14 @@ METHOD(eap_method_t, get_msk, status_t, return FAILED; } -METHOD(eap_method_t, get_identifier, u_int8_t, +METHOD(eap_method_t, get_identifier, uint8_t, private_eap_tnc_t *this) { return this->tls_eap->get_identifier(this->tls_eap); } METHOD(eap_method_t, set_identifier, void, - private_eap_tnc_t *this, u_int8_t identifier) + private_eap_tnc_t *this, uint8_t identifier) { this->tls_eap->set_identifier(this->tls_eap, identifier); } @@ -214,7 +219,7 @@ METHOD(eap_method_t, destroy, void, private_eap_tnc_t *this) { chunk_t pdp_server; - u_int16_t pdp_port; + uint16_t pdp_port; tls_t *tls; pdp_server = this->tnccs->get_pdp_server(this->tnccs, &pdp_port); @@ -245,13 +250,14 @@ METHOD(eap_inner_method_t, set_auth_type, void, * Generic private constructor */ static eap_tnc_t *eap_tnc_create(identification_t *server, - identification_t *peer, bool is_server) + identification_t *peer, bool is_server, + eap_type_t type) { private_eap_tnc_t *this; int max_msg_count; char* protocol; tnccs_t *tnccs; - tnccs_type_t type; + tnccs_type_t tnccs_type; INIT(this, .public = { @@ -270,24 +276,25 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, .set_auth_type = _set_auth_type, }, }, + .type = type, ); max_msg_count = lib->settings->get_int(lib->settings, "%s.plugins.eap-tnc.max_message_count", EAP_TNC_MAX_MESSAGE_COUNT, lib->ns); protocol = lib->settings->get_str(lib->settings, - "%s.plugins.eap-tnc.protocol", "tnccs-1.1", lib->ns); + "%s.plugins.eap-tnc.protocol", "tnccs-2.0", lib->ns); if (strcaseeq(protocol, "tnccs-2.0")) { - type = TNCCS_2_0; + tnccs_type = TNCCS_2_0; } else if (strcaseeq(protocol, "tnccs-1.1")) { - type = TNCCS_1_1; + tnccs_type = TNCCS_1_1; } else if (strcaseeq(protocol, "tnccs-dynamic") && is_server) { - type = TNCCS_DYNAMIC; + tnccs_type = TNCCS_DYNAMIC; } else { @@ -295,8 +302,9 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, free(this); return NULL; } - tnccs = tnc->tnccs->create_instance(tnc->tnccs, type, - is_server, server, peer, TNC_IFT_EAP_1_1, + tnccs = tnc->tnccs->create_instance(tnc->tnccs, tnccs_type, + is_server, server, peer, + (type == EAP_TNC) ? TNC_IFT_EAP_1_1 : TNC_IFT_EAP_2_0, is_server ? enforce_recommendation : NULL); if (!tnccs) { @@ -305,7 +313,7 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, return NULL; } this->tnccs = tnccs->get_ref(tnccs); - this->tls_eap = tls_eap_create(EAP_TNC, &tnccs->tls, + this->tls_eap = tls_eap_create(type, &tnccs->tls, EAP_TNC_MAX_MESSAGE_LEN, max_msg_count, FALSE); if (!this->tls_eap) @@ -319,11 +327,23 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, eap_tnc_t *eap_tnc_create_server(identification_t *server, identification_t *peer) { - return eap_tnc_create(server, peer, TRUE); + return eap_tnc_create(server, peer, TRUE, EAP_TNC); } eap_tnc_t *eap_tnc_create_peer(identification_t *server, identification_t *peer) { - return eap_tnc_create(server, peer, FALSE); + return eap_tnc_create(server, peer, FALSE, EAP_TNC); +} + +eap_tnc_t *eap_tnc_pt_create_server(identification_t *server, + identification_t *peer) +{ + return eap_tnc_create(server, peer, TRUE, EAP_PT_EAP); +} + +eap_tnc_t *eap_tnc_pt_create_peer(identification_t *server, + identification_t *peer) +{ + return eap_tnc_create(server, peer, FALSE, EAP_PT_EAP); } diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.h b/src/libcharon/plugins/eap_tnc/eap_tnc.h index 8c881f6cf..d7ea9f4bb 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc.h +++ b/src/libcharon/plugins/eap_tnc/eap_tnc.h @@ -26,7 +26,7 @@ typedef struct eap_tnc_t eap_tnc_t; #include <sa/eap/eap_inner_method.h> /** - * Implementation of the eap_method_t interface using EAP-TNC. + * Implementation of the eap_method_t interface using EAP-TNC or PT-EAP. */ struct eap_tnc_t { @@ -43,7 +43,8 @@ struct eap_tnc_t { * @param peer ID of the EAP client * @return eap_tnc_t object */ -eap_tnc_t *eap_tnc_create_server(identification_t *server, identification_t *peer); +eap_tnc_t *eap_tnc_create_server(identification_t *server, + identification_t *peer); /** * Creates the EAP method EAP-TNC acting as peer. @@ -52,6 +53,27 @@ eap_tnc_t *eap_tnc_create_server(identification_t *server, identification_t *pee * @param peer ID of the EAP client * @return eap_tnc_t object */ -eap_tnc_t *eap_tnc_create_peer(identification_t *server, identification_t *peer); +eap_tnc_t *eap_tnc_create_peer(identification_t *server, + identification_t *peer); + +/** + * Creates the EAP method PT-EAP acting as server. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_tnc_t object + */ +eap_tnc_t *eap_tnc_pt_create_server(identification_t *server, + identification_t *peer); + +/** + * Creates the EAP method PT-EAP acting as peer. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_tnc_t object + */ +eap_tnc_t *eap_tnc_pt_create_peer(identification_t *server, + identification_t *peer); #endif /** EAP_TNC_H_ @}*/ diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc_plugin.c b/src/libcharon/plugins/eap_tnc/eap_tnc_plugin.c index 813a75f48..d0f79fa43 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc_plugin.c +++ b/src/libcharon/plugins/eap_tnc/eap_tnc_plugin.c @@ -36,6 +36,14 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(EAP_PEER, EAP_TNC), PLUGIN_DEPENDS(EAP_PEER, EAP_TTLS), PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"), + PLUGIN_CALLBACK(eap_method_register, eap_tnc_pt_create_server), + PLUGIN_PROVIDE(EAP_SERVER, EAP_PT_EAP), + PLUGIN_DEPENDS(EAP_SERVER, EAP_TTLS), + PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"), + PLUGIN_CALLBACK(eap_method_register, eap_tnc_pt_create_peer), + PLUGIN_PROVIDE(EAP_PEER, EAP_PT_EAP), + PLUGIN_DEPENDS(EAP_PEER, EAP_TTLS), + PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"), }; *features = f; return countof(f); diff --git a/src/libcharon/plugins/eap_ttls/Makefile.am b/src/libcharon/plugins/eap_ttls/Makefile.am index 81776d800..3a7a8cda3 100644 --- a/src/libcharon/plugins/eap_ttls/Makefile.am +++ b/src/libcharon/plugins/eap_ttls/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libradius AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-ttls.la diff --git a/src/libcharon/plugins/eap_ttls/Makefile.in b/src/libcharon/plugins/eap_ttls/Makefile.in index b6937877d..70cc18405 100644 --- a/src/libcharon/plugins/eap_ttls/Makefile.in +++ b/src/libcharon/plugins/eap_ttls/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -268,6 +268,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -286,6 +287,7 @@ 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@ @@ -313,6 +315,7 @@ 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@ @@ -404,6 +407,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -422,7 +426,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libradius AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-ttls.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-ttls.la diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c index 88c2b88c6..9d145ea91 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2010 Andreas Steffen - * Copyright (C) 2010 HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2010-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -107,22 +107,34 @@ static status_t start_phase2_auth(private_eap_ttls_server_t *this) } /** - * If configured, start EAP-TNC protocol + * If configured, start PT-EAP or legacy EAP-TNC protocol */ static status_t start_phase2_tnc(private_eap_ttls_server_t *this, eap_type_t auth_type) { eap_inner_method_t *inner_method; + eap_type_t type; + char *eap_type_str; if (this->start_phase2_tnc && lib->settings->get_bool(lib->settings, "%s.plugins.eap-ttls.phase2_tnc", FALSE, lib->ns)) { - DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, EAP_TNC); - this->method = charon->eap->create_instance(charon->eap, EAP_TNC, + eap_type_str = lib->settings->get_str(lib->settings, + "%s.plugins.eap-ttls.phase2_tnc_method", "pt", + lib->ns); + type = eap_type_from_string(eap_type_str); + if (type == 0) + { + DBG1(DBG_IKE, "unrecognized phase2 EAP TNC method \"%s\"", + eap_type_str); + return FAILED; + } + DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, type); + this->method = charon->eap->create_instance(charon->eap, type, 0, EAP_SERVER, this->server, this->peer); if (this->method == NULL) { - DBG1(DBG_IKE, "%N method not available", eap_type_names, EAP_TNC); + DBG1(DBG_IKE, "%N method not available", eap_type_names, type); return FAILED; } inner_method = (eap_inner_method_t *)this->method; @@ -135,7 +147,7 @@ static status_t start_phase2_tnc(private_eap_ttls_server_t *this, } else { - DBG1(DBG_IKE, "%N method failed", eap_type_names, EAP_TNC); + DBG1(DBG_IKE, "%N method failed", eap_type_names, type); return FAILED; } } @@ -151,7 +163,7 @@ METHOD(tls_application_t, process, status_t, eap_payload_t *in; eap_code_t code; eap_type_t type = EAP_NAK, received_type; - u_int32_t vendor, received_vendor; + uint32_t vendor, received_vendor; status = this->avp->process(this->avp, reader, &data); switch (status) @@ -297,7 +309,7 @@ METHOD(tls_application_t, build, status_t, chunk_t data; eap_code_t code; eap_type_t type; - u_int32_t vendor; + uint32_t vendor; if (this->method == NULL && this->start_phase2 && lib->settings->get_bool(lib->settings, diff --git a/src/libcharon/plugins/error_notify/Makefile.am b/src/libcharon/plugins/error_notify/Makefile.am index 980fe1fbd..1c64bd2cc 100644 --- a/src/libcharon/plugins/error_notify/Makefile.am +++ b/src/libcharon/plugins/error_notify/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-error-notify.la diff --git a/src/libcharon/plugins/error_notify/Makefile.in b/src/libcharon/plugins/error_notify/Makefile.in index 8dd787569..0782dde53 100644 --- a/src/libcharon/plugins/error_notify/Makefile.in +++ b/src/libcharon/plugins/error_notify/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -274,6 +274,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -292,6 +293,7 @@ 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@ @@ -319,6 +321,7 @@ 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@ @@ -410,6 +413,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -427,7 +431,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-error-notify.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-error-notify.la diff --git a/src/libcharon/plugins/farp/Makefile.am b/src/libcharon/plugins/farp/Makefile.am index 95e57d8e6..0d862b0a9 100644 --- a/src/libcharon/plugins/farp/Makefile.am +++ b/src/libcharon/plugins/farp/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-farp.la diff --git a/src/libcharon/plugins/farp/Makefile.in b/src/libcharon/plugins/farp/Makefile.in index 13f0e5260..75ff158a8 100644 --- a/src/libcharon/plugins/farp/Makefile.in +++ b/src/libcharon/plugins/farp/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -264,6 +264,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -282,6 +283,7 @@ 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@ @@ -309,6 +311,7 @@ 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@ @@ -400,6 +403,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -416,7 +420,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-farp.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-farp.la diff --git a/src/libcharon/plugins/ha/Makefile.am b/src/libcharon/plugins/ha/Makefile.am index c10f7f903..50d342389 100644 --- a/src/libcharon/plugins/ha/Makefile.am +++ b/src/libcharon/plugins/ha/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-ha.la diff --git a/src/libcharon/plugins/ha/Makefile.in b/src/libcharon/plugins/ha/Makefile.in index d7a77ee17..cec73620a 100644 --- a/src/libcharon/plugins/ha/Makefile.in +++ b/src/libcharon/plugins/ha/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -419,7 +423,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-ha.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-ha.la diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 1ce9d3a16..6ff24c334 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -245,13 +245,8 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message { if (old_sa) { - peer_cfg_t *peer_cfg = old_sa->get_peer_cfg(old_sa); - - if (peer_cfg) - { - ike_sa->set_peer_cfg(ike_sa, peer_cfg); - ike_sa->inherit(ike_sa, old_sa); - } + ike_sa->inherit_pre(ike_sa, old_sa); + ike_sa->inherit_post(ike_sa, old_sa); charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, old_sa); old_sa = NULL; @@ -1077,4 +1072,3 @@ ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket, return &this->public; } - diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index 74147e553..dd2399366 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -207,6 +207,7 @@ static void setup_tunnel(private_ha_tunnel_t *this, charon->socket->get_port(charon->socket, FALSE), remote, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); peer_cfg = peer_cfg_create("ha", ike_cfg, CERT_NEVER_SEND, UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, TRUE, 30, 0, FALSE, NULL, NULL); @@ -235,6 +236,7 @@ static void setup_tunnel(private_ha_tunnel_t *this, ts = traffic_selector_create_dynamic(IPPROTO_ICMP, 0, 65535); child_cfg->add_traffic_selector(child_cfg, FALSE, ts); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP)); peer_cfg->add_child_cfg(peer_cfg, child_cfg); this->backend.cfg = peer_cfg; diff --git a/src/libcharon/plugins/ipseckey/Makefile.am b/src/libcharon/plugins/ipseckey/Makefile.am index 3a69e521f..aed63c122 100644 --- a/src/libcharon/plugins/ipseckey/Makefile.am +++ b/src/libcharon/plugins/ipseckey/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-ipseckey.la diff --git a/src/libcharon/plugins/ipseckey/Makefile.in b/src/libcharon/plugins/ipseckey/Makefile.in index 1f62f4026..da2e8d7fb 100644 --- a/src/libcharon/plugins/ipseckey/Makefile.in +++ b/src/libcharon/plugins/ipseckey/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-ipseckey.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-ipseckey.la diff --git a/src/libcharon/plugins/kernel_iph/Makefile.am b/src/libcharon/plugins/kernel_iph/Makefile.am new file mode 100644 index 000000000..56946ae1f --- /dev/null +++ b/src/libcharon/plugins/kernel_iph/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-kernel-iph.la +else +plugin_LTLIBRARIES = libstrongswan-kernel-iph.la +endif + +libstrongswan_kernel_iph_la_SOURCES = \ + kernel_iph_plugin.h kernel_iph_plugin.c \ + kernel_iph_net.h kernel_iph_net.c + +libstrongswan_kernel_iph_la_LDFLAGS = -module -avoid-version +libstrongswan_kernel_iph_la_LIBADD = -liphlpapi diff --git a/src/libcharon/plugins/kernel_iph/Makefile.in b/src/libcharon/plugins/kernel_iph/Makefile.in new file mode 100644 index 000000000..460c7b730 --- /dev/null +++ b/src/libcharon/plugins/kernel_iph/Makefile.in @@ -0,0 +1,768 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libcharon/plugins/kernel_iph +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(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 = +CONFIG_CLEAN_VPATH_FILES = +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; }; \ + } +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_kernel_iph_la_DEPENDENCIES = +am_libstrongswan_kernel_iph_la_OBJECTS = kernel_iph_plugin.lo \ + kernel_iph_net.lo +libstrongswan_kernel_iph_la_OBJECTS = \ + $(am_libstrongswan_kernel_iph_la_OBJECTS) +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 = +libstrongswan_kernel_iph_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_kernel_iph_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_kernel_iph_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_kernel_iph_la_rpath = +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 = $(libstrongswan_kernel_iph_la_SOURCES) +DIST_SOURCES = $(libstrongswan_kernel_iph_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# 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@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-kernel-iph.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-kernel-iph.la +libstrongswan_kernel_iph_la_SOURCES = \ + kernel_iph_plugin.h kernel_iph_plugin.c \ + kernel_iph_net.h kernel_iph_net.c + +libstrongswan_kernel_iph_la_LDFLAGS = -module -avoid-version +libstrongswan_kernel_iph_la_LIBADD = -liphlpapi +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/kernel_iph/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/kernel_iph/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): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libstrongswan-kernel-iph.la: $(libstrongswan_kernel_iph_la_OBJECTS) $(libstrongswan_kernel_iph_la_DEPENDENCIES) $(EXTRA_libstrongswan_kernel_iph_la_DEPENDENCIES) + $(AM_V_CCLD)$(libstrongswan_kernel_iph_la_LINK) $(am_libstrongswan_kernel_iph_la_rpath) $(libstrongswan_kernel_iph_la_OBJECTS) $(libstrongswan_kernel_iph_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_iph_net.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_iph_plugin.Plo@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 + +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: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(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-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + 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-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-pluginLTLIBRARIES install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c new file mode 100644 index 000000000..a4be4041e --- /dev/null +++ b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c @@ -0,0 +1,775 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* Windows 7, for some iphlpapi.h functionality */ +#define _WIN32_WINNT 0x0601 +#include <winsock2.h> +#include <ws2ipdef.h> +#include <windows.h> +#include <ntddndis.h> +#include <naptypes.h> +#include <iphlpapi.h> + +#include "kernel_iph_net.h" + +#include <hydra.h> +#include <threading/mutex.h> +#include <collections/linked_list.h> +#include <processing/jobs/callback_job.h> + + +/** delay before firing roam events (ms) */ +#define ROAM_DELAY 500 + +typedef struct private_kernel_iph_net_t private_kernel_iph_net_t; + +/** + * Private data of kernel_iph_net implementation. + */ +struct private_kernel_iph_net_t { + + /** + * Public interface. + */ + kernel_iph_net_t public; + + /** + * NotifyIpInterfaceChange() handle + */ + HANDLE changes; + + /** + * EnableRouter() OVERLAPPED + */ + OVERLAPPED router; + + /** + * Mutex to access interface list + */ + mutex_t *mutex; + + /** + * Known interfaces, as iface_t + */ + linked_list_t *ifaces; + + /** + * Earliest time of the next roam event + */ + timeval_t roam_next; + + /** + * Roam event due to address change? + */ + bool roam_address; +}; + +/** + * Interface entry + */ +typedef struct { + /** interface index */ + DWORD ifindex; + /** interface name */ + char *ifname; + /** interface description */ + char *ifdesc; + /** type of interface */ + DWORD iftype; + /** interface status */ + IF_OPER_STATUS status; + /** list of known addresses, as host_t */ + linked_list_t *addrs; +} iface_t; + +/** + * Clean up an iface_t + */ +static void iface_destroy(iface_t *this) +{ + this->addrs->destroy_offset(this->addrs, offsetof(host_t, destroy)); + free(this->ifname); + free(this->ifdesc); + free(this); +} + +/** + * Enum names for Windows IF_OPER_STATUS + */ +ENUM(if_oper_names, IfOperStatusUp, IfOperStatusLowerLayerDown, + "Up", + "Down", + "Testing", + "Unknown", + "Dormant", + "NotPresent", + "LowerLayerDown", +); + +/** + * Callback function that raises the delayed roam event + */ +static job_requeue_t roam_event(private_kernel_iph_net_t *this) +{ + bool address; + + this->mutex->lock(this->mutex); + address = this->roam_address; + this->roam_address = FALSE; + this->mutex->unlock(this->mutex); + + hydra->kernel_interface->roam(hydra->kernel_interface, address); + return JOB_REQUEUE_NONE; +} + +/** + * Fire delayed roam event, caller should hold mutex + */ +static void fire_roam_event(private_kernel_iph_net_t *this, bool address) +{ + timeval_t now; + + time_monotonic(&now); + this->roam_address |= address; + if (timercmp(&now, &this->roam_next, >)) + { + timeval_add_ms(&now, ROAM_DELAY); + this->roam_next = now; + lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*) + callback_job_create((callback_job_cb_t)roam_event, + this, NULL, NULL), + ROAM_DELAY); + } +} + +/** + * Update addresses for an iface entry + */ +static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry, + IP_ADAPTER_ADDRESSES *addr, bool log) +{ + IP_ADAPTER_UNICAST_ADDRESS *current; + enumerator_t *enumerator; + linked_list_t *list; + host_t *host, *old; + bool changes = FALSE; + + list = entry->addrs; + entry->addrs = linked_list_create(); + + for (current = addr->FirstUnicastAddress; current; current = current->Next) + { + if (current->Address.lpSockaddr->sa_family == AF_INET6) + { + struct sockaddr_in6 *sin; + + sin = (struct sockaddr_in6*)current->Address.lpSockaddr; + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) + { + continue; + } + } + + host = host_create_from_sockaddr(current->Address.lpSockaddr); + if (host) + { + bool found = FALSE; + + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &old)) + { + if (host->ip_equals(host, old)) + { + list->remove_at(list, enumerator); + old->destroy(old); + found = TRUE; + } + } + enumerator->destroy(enumerator); + + entry->addrs->insert_last(entry->addrs, host); + + if (!found && log) + { + DBG1(DBG_KNL, "%H appeared on interface %u '%s'", + host, entry->ifindex, entry->ifdesc); + changes = TRUE; + } + } + } + + while (list->remove_first(list, (void**)&old) == SUCCESS) + { + if (log) + { + DBG1(DBG_KNL, "%H disappeared from interface %u '%s'", + old, entry->ifindex, entry->ifdesc); + changes = TRUE; + } + old->destroy(old); + } + list->destroy(list); + + if (changes) + { + fire_roam_event(this, TRUE); + } +} + +/** + * Add an interface entry + */ +static void add_interface(private_kernel_iph_net_t *this, + IP_ADAPTER_ADDRESSES *addr, bool log) +{ + enumerator_t *enumerator; + iface_t *entry; + bool exists = FALSE; + + this->mutex->lock(this->mutex); + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->ifindex == addr->IfIndex) + { + exists = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + if (!exists) + { + char desc[128] = ""; + + wcstombs(desc, addr->Description, sizeof(desc)); + + INIT(entry, + .ifindex = addr->IfIndex, + .ifname = strdup(addr->AdapterName), + .ifdesc = strdup(desc), + .iftype = addr->IfType, + .status = addr->OperStatus, + .addrs = linked_list_create(), + ); + + if (log) + { + DBG1(DBG_KNL, "interface %u '%s' appeared", + entry->ifindex, entry->ifdesc); + } + + this->mutex->lock(this->mutex); + update_addrs(this, entry, addr, log); + this->ifaces->insert_last(this->ifaces, entry); + this->mutex->unlock(this->mutex); + } +} + +/** + * Remove an interface entry that is gone + */ +static void remove_interface(private_kernel_iph_net_t *this, NET_IFINDEX index) +{ + enumerator_t *enumerator; + iface_t *entry; + + this->mutex->lock(this->mutex); + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->ifindex == index) + { + this->ifaces->remove_at(this->ifaces, enumerator); + DBG1(DBG_KNL, "interface %u '%s' disappeared", + entry->ifindex, entry->ifdesc); + iface_destroy(entry); + fire_roam_event(this, TRUE); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Update an interface entry changed + */ +static void update_interface(private_kernel_iph_net_t *this, + IP_ADAPTER_ADDRESSES *addr) +{ + enumerator_t *enumerator; + iface_t *entry; + + this->mutex->lock(this->mutex); + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->ifindex == addr->IfIndex) + { + if (entry->status != addr->OperStatus) + { + DBG1(DBG_KNL, "interface %u '%s' changed state from %N to %N", + entry->ifindex, entry->ifdesc, if_oper_names, + entry->status, if_oper_names, addr->OperStatus); + entry->status = addr->OperStatus; + fire_roam_event(this, TRUE); + } + update_addrs(this, entry, addr, TRUE); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * MinGW gets MIB_IPINTERFACE_ROW wrong, as it packs InterfaceLuid just after + * Family. Fix that with our own version of the struct header. + */ +typedef struct { + ADDRESS_FAMILY Family; + union { + ULONG64 Value; + struct { + ULONG64 Reserved :24; + ULONG64 NetLuidIndex :24; + ULONG64 IfType :16; + } Info; + } InterfaceLuid; + NET_IFINDEX InterfaceIndex; + /* more would go here if needed */ +} MIB_IPINTERFACE_ROW_FIXUP; + +/** + * NotifyIpInterfaceChange() callback + */ +static void WINAPI change_interface(void *user, PMIB_IPINTERFACE_ROW row_badal, + MIB_NOTIFICATION_TYPE type) +{ + private_kernel_iph_net_t *this = user; + MIB_IPINTERFACE_ROW_FIXUP* row = (MIB_IPINTERFACE_ROW_FIXUP*)row_badal; + IP_ADAPTER_ADDRESSES addrs[64], *current; + ULONG res, size = sizeof(addrs); + + if (row && type == MibDeleteInstance) + { + remove_interface(this, row->InterfaceIndex); + } + else + { + res = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, + NULL, addrs, &size); + if (res == NO_ERROR) + { + current = addrs; + while (current) + { + /* row is NULL only on MibInitialNotification */ + if (!row || row->InterfaceIndex == current->IfIndex) + { + switch (type) + { + case MibParameterNotification: + update_interface(this, current); + break; + case MibInitialNotification: + add_interface(this, current, FALSE); + break; + case MibAddInstance: + add_interface(this, current, TRUE); + break; + default: + break; + } + } + current = current->Next; + } + } + else + { + DBG1(DBG_KNL, "getting IPH adapter addresses failed: 0x%08lx", res); + } + } +} + +/** + * Get an iface entry for a local address, does no locking + */ +static iface_t* address2entry(private_kernel_iph_net_t *this, host_t *ip) +{ + enumerator_t *ifaces, *addrs; + iface_t *entry, *found = NULL; + host_t *host; + + ifaces = this->ifaces->create_enumerator(this->ifaces); + while (!found && ifaces->enumerate(ifaces, &entry)) + { + addrs = entry->addrs->create_enumerator(entry->addrs); + while (!found && addrs->enumerate(addrs, &host)) + { + if (host->ip_equals(host, ip)) + { + found = entry; + } + } + addrs->destroy(addrs); + } + ifaces->destroy(ifaces); + + return found; +} + +METHOD(kernel_net_t, get_interface_name, bool, + private_kernel_iph_net_t *this, host_t* ip, char **name) +{ + iface_t *entry; + + this->mutex->lock(this->mutex); + entry = address2entry(this, ip); + if (entry && name) + { + *name = strdup(entry->ifname); + } + this->mutex->unlock(this->mutex); + + return entry != NULL; +} + +/** + * Address enumerator + */ +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** what kind of address should we enumerate? */ + kernel_address_type_t which; + /** enumerator over interfaces */ + enumerator_t *ifaces; + /** current enumerator over addresses, or NULL */ + enumerator_t *addrs; + /** mutex to unlock on destruction */ + mutex_t *mutex; +} addr_enumerator_t; + +METHOD(enumerator_t, addr_enumerate, bool, + addr_enumerator_t *this, host_t **host) +{ + iface_t *entry; + + while (TRUE) + { + while (!this->addrs) + { + if (!this->ifaces->enumerate(this->ifaces, &entry)) + { + return FALSE; + } + if (entry->iftype == IF_TYPE_SOFTWARE_LOOPBACK && + !(this->which & ADDR_TYPE_LOOPBACK)) + { + continue; + } + if (entry->status != IfOperStatusUp && + !(this->which & ADDR_TYPE_DOWN)) + { + continue; + } + this->addrs = entry->addrs->create_enumerator(entry->addrs); + } + if (this->addrs->enumerate(this->addrs, host)) + { + return TRUE; + } + this->addrs->destroy(this->addrs); + this->addrs = NULL; + } +} + +METHOD(enumerator_t, addr_destroy, void, + addr_enumerator_t *this) +{ + DESTROY_IF(this->addrs); + this->ifaces->destroy(this->ifaces); + this->mutex->unlock(this->mutex); + free(this); +} + +METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, + private_kernel_iph_net_t *this, kernel_address_type_t which) +{ + addr_enumerator_t *enumerator; + + if (!(which & ADDR_TYPE_REGULAR)) + { + /* we currently have no virtual, but regular IPs only */ + return enumerator_create_empty(); + } + + this->mutex->lock(this->mutex); + + INIT(enumerator, + .public = { + .enumerate = (void*)_addr_enumerate, + .destroy = _addr_destroy, + }, + .which = which, + .ifaces = this->ifaces->create_enumerator(this->ifaces), + .mutex = this->mutex, + ); + return &enumerator->public; +} + +METHOD(kernel_net_t, get_source_addr, host_t*, + private_kernel_iph_net_t *this, host_t *dest, host_t *src) +{ + MIB_IPFORWARD_ROW2 route; + SOCKADDR_INET best, *sai_dst, *sai_src = NULL; + DWORD res, index = 0; + + res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index); + if (res != NO_ERROR) + { + DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res); + return NULL; + } + + sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest); + if (src) + { + sai_src = (SOCKADDR_INET*)src->get_sockaddr(src); + } + res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best); + if (res != NO_ERROR) + { + DBG2(DBG_KNL, "getting src address to %H failed: 0x%08x", dest, res); + return NULL; + } + return host_create_from_sockaddr((struct sockaddr*)&best); +} + +METHOD(kernel_net_t, get_nexthop, host_t*, + private_kernel_iph_net_t *this, host_t *dest, int prefix, host_t *src) +{ + MIB_IPFORWARD_ROW2 route; + SOCKADDR_INET best, *sai_dst, *sai_src = NULL; + DWORD res, index = 0; + host_t *nexthop; + + res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index); + if (res != NO_ERROR) + { + DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res); + return NULL; + } + + sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest); + if (src) + { + sai_src = (SOCKADDR_INET*)src->get_sockaddr(src); + } + res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best); + if (res != NO_ERROR) + { + DBG2(DBG_KNL, "getting nexthop to %H failed: 0x%08x", dest, res); + return NULL; + } + nexthop = host_create_from_sockaddr((struct sockaddr*)&route.NextHop); + if (nexthop) + { + if (!nexthop->is_anyaddr(nexthop)) + { + return nexthop; + } + nexthop->destroy(nexthop); + } + return NULL; +} + +METHOD(kernel_net_t, add_ip, status_t, + private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix, + char *iface_name) +{ + return NOT_SUPPORTED; +} + +METHOD(kernel_net_t, del_ip, status_t, + private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix, + bool wait) +{ + return NOT_SUPPORTED; +} + +/** + * Add or remove a route + */ +static status_t manage_route(private_kernel_iph_net_t *this, bool add, + chunk_t dst, u_int8_t prefixlen, host_t *gtw, char *name) +{ + MIB_IPFORWARD_ROW2 row = { + .DestinationPrefix = { + .PrefixLength = prefixlen, + }, + .SitePrefixLength = prefixlen, + .ValidLifetime = INFINITE, + .PreferredLifetime = INFINITE, + .Metric = 10, + .Protocol = MIB_IPPROTO_NETMGMT, + }; + enumerator_t *enumerator; + iface_t *entry; + ULONG ret; + + this->mutex->lock(this->mutex); + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, &entry)) + { + if (streq(name, entry->ifname)) + { + row.InterfaceIndex = entry->ifindex; + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + if (!row.InterfaceIndex) + { + return NOT_FOUND; + } + switch (dst.len) + { + case 4: + row.DestinationPrefix.Prefix.si_family = AF_INET; + memcpy(&row.DestinationPrefix.Prefix.Ipv4.sin_addr, + dst.ptr, dst.len); + break; + case 16: + row.DestinationPrefix.Prefix.si_family = AF_INET6; + memcpy(&row.DestinationPrefix.Prefix.Ipv6.sin6_addr, + dst.ptr, dst.len); + break; + default: + return FAILED; + } + if (gtw) + { + memcpy(&row.NextHop, gtw->get_sockaddr(gtw), + *gtw->get_sockaddr_len(gtw)); + } + + if (add) + { + ret = CreateIpForwardEntry2(&row); + } + else + { + ret = DeleteIpForwardEntry2(&row); + } + if (ret != NO_ERROR) + { + DBG1(DBG_KNL, "%sing route failed: 0x%08lx", add ? "add" : "remov", ret); + return FAILED; + } + + if (add) + { + ret = EnableRouter(NULL, &this->router); + if (ret != ERROR_IO_PENDING) + { + DBG1(DBG_KNL, "EnableRouter router failed: 0x%08lx", ret); + } + } + else + { + ret = UnenableRouter(&this->router, NULL); + if (ret != NO_ERROR) + { + DBG1(DBG_KNL, "UnenableRouter router failed: 0x%08lx", ret); + } + } + return SUCCESS; +} + +METHOD(kernel_net_t, add_route, status_t, + private_kernel_iph_net_t *this, chunk_t dst, u_int8_t prefixlen, + host_t *gateway, host_t *src, char *name) +{ + return manage_route(this, TRUE, dst, prefixlen, gateway, name); +} + +METHOD(kernel_net_t, del_route, status_t, + private_kernel_iph_net_t *this, chunk_t dst, u_int8_t prefixlen, + host_t *gateway, host_t *src, char *name) +{ + return manage_route(this, FALSE, dst, prefixlen, gateway, name); +} + +METHOD(kernel_net_t, destroy, void, + private_kernel_iph_net_t *this) +{ + if (this->changes) + { + CancelMibChangeNotify2(this->changes); + } + CloseHandle(this->router.hEvent); + this->mutex->destroy(this->mutex); + this->ifaces->destroy_function(this->ifaces, (void*)iface_destroy); + free(this); +} + +/* + * Described in header. + */ +kernel_iph_net_t *kernel_iph_net_create() +{ + private_kernel_iph_net_t *this; + ULONG res; + + INIT(this, + .public = { + .interface = { + .get_interface = _get_interface_name, + .create_address_enumerator = _create_address_enumerator, + .get_source_addr = _get_source_addr, + .get_nexthop = _get_nexthop, + .add_ip = _add_ip, + .del_ip = _del_ip, + .add_route = _add_route, + .del_route = _del_route, + .destroy = _destroy, + }, + }, + .router = { + .hEvent = CreateEvent(NULL, FALSE, FALSE, NULL), + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .ifaces = linked_list_create(), + ); + /* PIPINTERFACE_CHANGE_CALLBACK is not using WINAPI in MinGW, which seems + * to be wrong. Force a cast to our WINAPI call */ + res = NotifyIpInterfaceChange(AF_UNSPEC, (void*)change_interface, + this, TRUE, &this->changes); + if (res != NO_ERROR) + { + DBG1(DBG_KNL, "registering for IPH interface changes failed: 0x%08lx", + res); + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libcharon/plugins/kernel_iph/kernel_iph_net.h b/src/libcharon/plugins/kernel_iph/kernel_iph_net.h new file mode 100644 index 000000000..c8f35de18 --- /dev/null +++ b/src/libcharon/plugins/kernel_iph/kernel_iph_net.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup kernel_iph_net_i kernel_iph_net + * @{ @ingroup kernel_iph + */ + +#ifndef KERNEL_IPH_NET_H_ +#define KERNEL_IPH_NET_H_ + +#include <kernel/kernel_net.h> + +typedef struct kernel_iph_net_t kernel_iph_net_t; + +/** + * Implementation of the kernel network interface using Windows IP Helper. + */ +struct kernel_iph_net_t { + + /** + * Implements kernel_net_t interface + */ + kernel_net_t interface; +}; + +/** + * Create IP Helper network backend instance. + * + * @return kernel_iph_net_t instance + */ +kernel_iph_net_t *kernel_iph_net_create(); + +#endif /** KERNEL_IPH_NET_H_ @}*/ diff --git a/src/libcharon/plugins/kernel_iph/kernel_iph_plugin.c b/src/libcharon/plugins/kernel_iph/kernel_iph_plugin.c new file mode 100644 index 000000000..c5475e30b --- /dev/null +++ b/src/libcharon/plugins/kernel_iph/kernel_iph_plugin.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + + +#include "kernel_iph_plugin.h" +#include "kernel_iph_net.h" + +#include <hydra.h> + +typedef struct private_kernel_iph_plugin_t private_kernel_iph_plugin_t; + +/** + * Private data of kernel iph plugin + */ +struct private_kernel_iph_plugin_t { + + /** + * Implements plugin interface + */ + kernel_iph_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_kernel_iph_plugin_t *this) +{ + return "kernel-iph"; +} + +METHOD(plugin_t, get_features, int, + private_kernel_iph_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(kernel_net_register, kernel_iph_net_create), + PLUGIN_PROVIDE(CUSTOM, "kernel-net"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_kernel_iph_plugin_t *this) +{ + free(this); +} + +/* + * See header file + */ +plugin_t *kernel_iph_plugin_create() +{ + private_kernel_iph_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/kernel_iph/kernel_iph_plugin.h b/src/libcharon/plugins/kernel_iph/kernel_iph_plugin.h new file mode 100644 index 000000000..616f90e77 --- /dev/null +++ b/src/libcharon/plugins/kernel_iph/kernel_iph_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup kernel_iph kernel_iph + * @ingroup cplugins + * + * @defgroup kernel_iph_plugin kernel_iph_plugin + * @{ @ingroup kernel_iph + */ + +#ifndef KERNEL_IPH_PLUGIN_H_ +#define KERNEL_IPH_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct kernel_iph_plugin_t kernel_iph_plugin_t; + +/** + * Windows IP Helper API based networking backend. + */ +struct kernel_iph_plugin_t { + + /** + * Implements plugin interface. + */ + plugin_t plugin; +}; + +#endif /** KERNEL_IPH_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/kernel_libipsec/Makefile.am b/src/libcharon/plugins/kernel_libipsec/Makefile.am index a39d06753..eca2b2325 100644 --- a/src/libcharon/plugins/kernel_libipsec/Makefile.am +++ b/src/libcharon/plugins/kernel_libipsec/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libipsec AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-kernel-libipsec.la diff --git a/src/libcharon/plugins/kernel_libipsec/Makefile.in b/src/libcharon/plugins/kernel_libipsec/Makefile.in index 3bc289d22..a4e5ba931 100644 --- a/src/libcharon/plugins/kernel_libipsec/Makefile.in +++ b/src/libcharon/plugins/kernel_libipsec/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -268,6 +268,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -286,6 +287,7 @@ 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@ @@ -313,6 +315,7 @@ 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@ @@ -404,6 +407,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -421,7 +425,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libipsec AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-kernel-libipsec.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-kernel-libipsec.la diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c index b33580700..bd07a67a2 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c @@ -252,8 +252,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t, private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, - u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, - u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound, + u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, + u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window, + bool initiator, bool encap, bool esn, bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts) { return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, mark, @@ -313,7 +314,7 @@ static void add_exclude_route(private_kernel_libipsec_ipsec_t *this, { DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src); gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface, - dst, NULL); + dst, -1, NULL); if (gtw) { char *if_name = NULL; @@ -444,7 +445,7 @@ static bool install_route(private_kernel_libipsec_ipsec_t *this, #ifndef __linux__ /* on Linux we cant't install a gateway */ route->gateway = hydra->kernel_interface->get_nexthop( - hydra->kernel_interface, dst, src); + hydra->kernel_interface, dst, -1, src); #endif if (policy->route) diff --git a/src/libcharon/plugins/kernel_wfp/Makefile.am b/src/libcharon/plugins/kernel_wfp/Makefile.am new file mode 100644 index 000000000..85e5089a3 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/Makefile.am @@ -0,0 +1,33 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-kernel-wfp.la +else +plugin_LTLIBRARIES = libstrongswan-kernel-wfp.la +endif + +libstrongswan_kernel_wfp_la_SOURCES = \ + kernel_wfp_plugin.h kernel_wfp_plugin.c \ + kernel_wfp_compat.c kernel_wfp_compat.h \ + kernel_wfp_ipsec.h kernel_wfp_ipsec.c + +libstrongswan_kernel_wfp_la_LDFLAGS = -module -avoid-version +libstrongswan_kernel_wfp_la_LIBADD = -lfwpuclnt + + +noinst_PROGRAMS = ipsecdump + +ipsecdump_SOURCES = \ + ipsecdump.c +ipsecdump_LDADD = \ + libstrongswan-kernel-wfp.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + + +EXTRA_DIST = mingw-w64-4.8.1.diff diff --git a/src/libcharon/plugins/kernel_wfp/Makefile.in b/src/libcharon/plugins/kernel_wfp/Makefile.in new file mode 100644 index 000000000..ff987f8d4 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/Makefile.in @@ -0,0 +1,801 @@ +# 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@ +noinst_PROGRAMS = ipsecdump$(EXEEXT) +subdir = src/libcharon/plugins/kernel_wfp +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(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 = +CONFIG_CLEAN_VPATH_FILES = +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; }; \ + } +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_kernel_wfp_la_DEPENDENCIES = +am_libstrongswan_kernel_wfp_la_OBJECTS = kernel_wfp_plugin.lo \ + kernel_wfp_compat.lo kernel_wfp_ipsec.lo +libstrongswan_kernel_wfp_la_OBJECTS = \ + $(am_libstrongswan_kernel_wfp_la_OBJECTS) +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 = +libstrongswan_kernel_wfp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_kernel_wfp_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_kernel_wfp_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_kernel_wfp_la_rpath = +PROGRAMS = $(noinst_PROGRAMS) +am_ipsecdump_OBJECTS = ipsecdump.$(OBJEXT) +ipsecdump_OBJECTS = $(am_ipsecdump_OBJECTS) +ipsecdump_DEPENDENCIES = libstrongswan-kernel-wfp.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +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 = $(libstrongswan_kernel_wfp_la_SOURCES) $(ipsecdump_SOURCES) +DIST_SOURCES = $(libstrongswan_kernel_wfp_la_SOURCES) \ + $(ipsecdump_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# 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@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-kernel-wfp.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-kernel-wfp.la +libstrongswan_kernel_wfp_la_SOURCES = \ + kernel_wfp_plugin.h kernel_wfp_plugin.c \ + kernel_wfp_compat.c kernel_wfp_compat.h \ + kernel_wfp_ipsec.h kernel_wfp_ipsec.c + +libstrongswan_kernel_wfp_la_LDFLAGS = -module -avoid-version +libstrongswan_kernel_wfp_la_LIBADD = -lfwpuclnt +ipsecdump_SOURCES = \ + ipsecdump.c + +ipsecdump_LDADD = \ + libstrongswan-kernel-wfp.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + +EXTRA_DIST = mingw-w64-4.8.1.diff +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/kernel_wfp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/kernel_wfp/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): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libstrongswan-kernel-wfp.la: $(libstrongswan_kernel_wfp_la_OBJECTS) $(libstrongswan_kernel_wfp_la_DEPENDENCIES) $(EXTRA_libstrongswan_kernel_wfp_la_DEPENDENCIES) + $(AM_V_CCLD)$(libstrongswan_kernel_wfp_la_LINK) $(am_libstrongswan_kernel_wfp_la_rpath) $(libstrongswan_kernel_wfp_la_OBJECTS) $(libstrongswan_kernel_wfp_la_LIBADD) $(LIBS) + +clean-noinstPROGRAMS: + @list='$(noinst_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 + +ipsecdump$(EXEEXT): $(ipsecdump_OBJECTS) $(ipsecdump_DEPENDENCIES) $(EXTRA_ipsecdump_DEPENDENCIES) + @rm -f ipsecdump$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(ipsecdump_OBJECTS) $(ipsecdump_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsecdump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_wfp_compat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_wfp_ipsec.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_wfp_plugin.Plo@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 + +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: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-noinstPROGRAMS clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(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-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ + clean-pluginLTLIBRARIES 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-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/kernel_wfp/ipsecdump.c b/src/libcharon/plugins/kernel_wfp/ipsecdump.c new file mode 100644 index 000000000..7ca7df5a1 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/ipsecdump.c @@ -0,0 +1,666 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* Windows 7, for some fwpmu.h functionality */ +#define _WIN32_WINNT 0x0601 + +#include "kernel_wfp_compat.h" + +#include <library.h> + +ENUM(auth_type_names, IPSEC_AUTH_MD5, IPSEC_AUTH_AES_256, + "MD5", + "SHA1", + "SHA256", + "AES128", + "AES192", + "AES256", +); + +ENUM(auth_config_names, 0, 5, + "HMAC96", + "HMAC96", + "HMAC128", + "GMAC", + "GMAC", + "GMAC", +); + +ENUM(cipher_type_names, IPSEC_CIPHER_TYPE_DES, IPSEC_CIPHER_TYPE_AES_256, + "DES", + "3DES", + "AES128", + "AES192", + "AES256", +); + +ENUM(cipher_config_names, 1, 8, + "CBC", + "CBC", + "CBC", + "CBC", + "CBC", + "GCM", + "GCM", + "GCM", +); + +ENUM(match_type_names, FWP_MATCH_EQUAL, FWP_MATCH_NOT_EQUAL, + "equals", + "greater", + "less than", + "greater or equal than", + "less or equal than", + "in range", + "has all flags set", + "has any flags set", + "has none flags set", + "equals case insensitive", + "not equal", +); + +ENUM(traffic_type_names, IPSEC_TRAFFIC_TYPE_TRANSPORT, IPSEC_TRAFFIC_TYPE_TUNNEL, + "Transport", + "Tunnel", +); + +/** + * Print a GUID to a static buffer + */ +static char *guid2string(GUID *guid) +{ + static char buf[64]; + + snprintf(buf, sizeof(buf), + "%08x,%04x,%04x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + + return buf; +} + +/** + * Convert filter condition key GUID to some known strings + */ +static char* cond2name(GUID *guid, bool *address) +{ + struct { + GUID guid; + char *name; + bool address; + } map[] = { + { FWPM_CONDITION_IP_LOCAL_ADDRESS, "local address", TRUE}, + { FWPM_CONDITION_IP_REMOTE_ADDRESS, "remote address", TRUE}, + { FWPM_CONDITION_IP_SOURCE_ADDRESS, "source address", TRUE}, + { FWPM_CONDITION_IP_DESTINATION_ADDRESS, "destination address", TRUE}, + { FWPM_CONDITION_IP_LOCAL_PORT, "local port", FALSE}, + { FWPM_CONDITION_IP_REMOTE_PORT, "remote port", FALSE}, + { FWPM_CONDITION_IP_PROTOCOL, "protocol", FALSE}, + { FWPM_CONDITION_ICMP_CODE, "icmp code", FALSE}, + { FWPM_CONDITION_ICMP_TYPE, "icmp type", FALSE}, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (memeq(&map[i].guid, guid, sizeof(GUID))) + { + *address = map[i].address; + return map[i].name; + } + } + *address = FALSE; + return guid2string(guid); +} + +/** + * Print a host from raw data and IP version + */ +static void print_host(FWP_IP_VERSION version, void *data) +{ + host_t *host = NULL; + UINT32 ints[4]; + + switch (version) + { + case FWP_IP_VERSION_V4: + ints[0] = untoh32(data); + host = host_create_from_chunk(AF_INET, chunk_from_thing(ints[0]), 0); + break; + case FWP_IP_VERSION_V6: + ints[3] = untoh32(data); + ints[2] = untoh32(data + 4); + ints[1] = untoh32(data + 8); + ints[0] = untoh32(data + 12); + host = host_create_from_chunk(AF_INET6, chunk_from_thing(ints), 0); + break; + default: + break; + } + if (host) + { + printf("%H", host); + host->destroy(host); + } +} + +/** + * Print IPSEC_SA_AUTH_INFORMATION0 + */ +static void print_auth(IPSEC_SA_AUTH_INFORMATION0 *a) +{ + printf("%N-%N", + auth_type_names, a->authTransform.authTransformId.authType, + auth_config_names, a->authTransform.authTransformId.authConfig); +} + +/** + * Print IPSEC_SA_CIPHER_INFORMATION0 + */ +static void print_cipher(IPSEC_SA_CIPHER_INFORMATION0 *c) +{ + printf("%N-%N", + cipher_type_names, c->cipherTransform.cipherTransformId.cipherType, + cipher_config_names, c->cipherTransform.cipherTransformId.cipherConfig); +} + +/** + * Print IPsec SA transform + */ +static void list_sa(HANDLE engine, IPSEC_SA0 *sa) +{ + printf(" SPI 0x%08x\n", sa->spi); + switch (sa->saTransformType) + { + case IPSEC_TRANSFORM_AH: + printf(" AH: "); + print_auth(sa->ahInformation); + break; + case IPSEC_TRANSFORM_ESP_AUTH: + printf(" ESP: "); + print_auth(sa->espAuthInformation); + break; + case IPSEC_TRANSFORM_ESP_CIPHER: + printf(" ESP: "); + print_cipher(sa->espCipherInformation); + break; + case IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER: + printf(" ESP: "); + print_auth(&sa->espAuthAndCipherInformation->saAuthInformation); + printf(", "); + print_cipher(&sa->espAuthAndCipherInformation->saCipherInformation); + break; + default: + printf(" (Transform %d)", sa->saTransformType); + break; + } + printf("\n"); +} + +/** + * List a filter condition value, optionally as IP address + */ +static void print_value(FWP_CONDITION_VALUE0 *value, bool address) +{ + chunk_t chunk; + + switch (value->type) + { + case FWP_EMPTY: + printf("empty"); + break; + case FWP_UINT8: + printf("%u", value->uint8); + break; + case FWP_UINT16: + printf("%u", value->uint16); + break; + case FWP_UINT32: + if (address) + { + print_host(FWP_IP_VERSION_V4, &value->uint32); + } + else + { + printf("%u", value->uint32); + } + break; + case FWP_UINT64: + printf("%llu", value->uint64); + break; + case FWP_INT8: + printf("%d", value->int8); + break; + case FWP_INT16: + printf("%d", value->int16); + break; + case FWP_INT32: + printf("%d", value->int32); + break; + case FWP_INT64: + printf("%lld", value->int64); + break; + case FWP_FLOAT: + printf("%f", value->float32); + break; + case FWP_DOUBLE: + printf("%lf", value->double64); + break; + case FWP_BYTE_ARRAY16_TYPE: + if (address) + { + print_host(FWP_IP_VERSION_V6, value->byteArray16); + } + else + { + chunk = chunk_create((u_char*)value->byteArray16, 16); + printf("%#B", &chunk); + } + break; + case FWP_BYTE_BLOB_TYPE: + chunk = chunk_create(value->byteBlob->data, value->byteBlob->size); + printf("%#B", &chunk); + break; + case FWP_V4_ADDR_MASK: + print_host(FWP_IP_VERSION_V4, &value->v4AddrMask->addr); + printf("/"); + print_host(FWP_IP_VERSION_V4, &value->v4AddrMask->mask); + break; + case FWP_V6_ADDR_MASK: + print_host(FWP_IP_VERSION_V6, &value->v6AddrMask->addr); + printf("/%u", &value->v6AddrMask->prefixLength); + break; + case FWP_RANGE_TYPE: + print_value((FWP_CONDITION_VALUE0*)&value->rangeValue->valueLow, + address); + printf(" - "); + print_value((FWP_CONDITION_VALUE0*)&value->rangeValue->valueHigh, + address); + break; + default: + printf("(unsupported)"); + break; + } +} + +/** + * List a filter condition + */ +static void list_cond(HANDLE engine, FWPM_FILTER_CONDITION0 *cond) +{ + bool address; + + printf(" '%s' %N '", cond2name(&cond->fieldKey, &address), + match_type_names, cond->matchType); + print_value(&cond->conditionValue, address); + printf("'\n"); +} + +/** + * Print IPsec SA details + */ +static void list_details(HANDLE engine, IPSEC_SA_DETAILS1 *details) +{ + int i; + + printf(" %sbound SA: ", + details->saDirection == FWP_DIRECTION_INBOUND ? "In" : "Out"); + print_host(details->traffic.ipVersion, &details->traffic.localV4Address); + printf(" %s ", details->saDirection == FWP_DIRECTION_INBOUND ? "<-" : "->"); + print_host(details->traffic.ipVersion, &details->traffic.remoteV4Address); + printf("\n %N, flags: 0x%06x, lifetime: %us\n", + traffic_type_names, details->traffic.trafficType, + details->saBundle.flags, details->saBundle.lifetime.lifetimeSeconds); + if (details->udpEncapsulation) + { + printf(" UDP encap ports %u - %u\n", + details->udpEncapsulation->localUdpEncapPort, + details->udpEncapsulation->remoteUdpEncapPort); + } + for (i = 0; i < details->saBundle.numSAs; i++) + { + list_sa(engine, &details->saBundle.saList[i]); + } + printf(" Filter ID %llu\n", details->transportFilter->filterId); + for (i = 0; i < details->transportFilter->numFilterConditions; i++) + { + list_cond(engine, &details->transportFilter->filterCondition[i]); + } +} + +/** + * List installed SA contexts + */ +static bool list_contexts(HANDLE engine) +{ + HANDLE handle; + UINT32 returned; + DWORD res; + IPSEC_SA_CONTEXT1 **entries; + + res = IPsecSaContextCreateEnumHandle0(engine, NULL, &handle); + if (res != ERROR_SUCCESS) + { + fprintf(stderr, "IPsecSaContextCreateEnumHandle0(): 0x%08x\n", res); + return FALSE; + } + + while (TRUE) + { + res = IPsecSaContextEnum1(engine, handle, 1, &entries, &returned); + if (res != ERROR_SUCCESS) + { + fprintf(stderr, "IPsecSaContextEnum1(): 0x%08x\n", res); + IPsecSaContextDestroyEnumHandle0(engine, handle); + return FALSE; + } + if (returned == 0) + { + break; + } + + printf("SA context %llu:\n", entries[0]->saContextId); + list_details(engine, entries[0]->inboundSa); + list_details(engine, entries[0]->outboundSa); + + FwpmFreeMemory0((void**)&entries); + } + IPsecSaContextDestroyEnumHandle0(engine, handle); + return TRUE; +} + +const GUID FWPM_LAYER_IPSEC_KM_DEMUX_V4 = { + 0xf02b1526, 0xa459, 0x4a51, { 0xb9, 0xe3, 0x75, 0x9d, 0xe5, 0x2b, 0x9d, 0x2c } +}; +const GUID FWPM_LAYER_IPSEC_KM_DEMUX_V6 = { + 0x2f755cf6, 0x2fd4, 0x4e88, { 0xb3, 0xe4, 0xa9, 0x1b, 0xca, 0x49, 0x52, 0x35 } +}; +const GUID FWPM_LAYER_IPSEC_V4 = { + 0xeda65c74, 0x610d, 0x4bc5, { 0x94, 0x8f, 0x3c, 0x4f, 0x89, 0x55, 0x68, 0x67 } +}; +const GUID FWPM_LAYER_IPSEC_V6 = { + 0x13c48442, 0x8d87, 0x4261, { 0x9a, 0x29, 0x59, 0xd2, 0xab, 0xc3, 0x48, 0xb4 } +}; +const GUID FWPM_LAYER_IKEEXT_V4 = { + 0xb14b7bdb, 0xdbbd, 0x473e, { 0xbe, 0xd4, 0x8b, 0x47, 0x08, 0xd4, 0xf2, 0x70 } +}; +const GUID FWPM_LAYER_IKEEXT_V6 = { + 0xb64786b3, 0xf687, 0x4eb9, { 0x89, 0xd2, 0x8e, 0xf3, 0x2a, 0xcd, 0xab, 0xe2 } +}; +const GUID FWPM_LAYER_INBOUND_IPPACKET_V4 = { + 0xc86fd1bf, 0x21cd, 0x497e, { 0xa0, 0xbb, 0x17, 0x42, 0x5c, 0x88, 0x5c, 0x58 } +}; +const GUID FWPM_LAYER_INBOUND_IPPACKET_V4_DISCARD = { + 0xb5a230d0, 0xa8c0, 0x44f2, { 0x91, 0x6e, 0x99, 0x1b, 0x53, 0xde, 0xd1, 0xf7 } +}; +const GUID FWPM_LAYER_INBOUND_IPPACKET_V6 = { + 0xf52032cb, 0x991c, 0x46e7, { 0x97, 0x1d, 0x26, 0x01, 0x45, 0x9a, 0x91, 0xca } +}; +const GUID FWPM_LAYER_INBOUND_IPPACKET_V6_DISCARD = { + 0xbb24c279, 0x93b4, 0x47a2, { 0x83, 0xad, 0xae, 0x16, 0x98, 0xb5, 0x08, 0x85 } +}; +const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V4 = { + 0x1e5c9fae, 0x8a84, 0x4135, { 0xa3, 0x31, 0x95, 0x0b, 0x54, 0x22, 0x9e, 0xcd } +}; +const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V4_DISCARD = { + 0x08e4bcb5, 0xb647, 0x48f3, { 0x95, 0x3c, 0xe5, 0xdd, 0xbd, 0x03, 0x93, 0x7e } +}; +const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V6 = { + 0xa3b3ab6b, 0x3564, 0x488c, { 0x91, 0x17, 0xf3, 0x4e, 0x82, 0x14, 0x27, 0x63 } +}; +const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD = { + 0x9513d7c4, 0xa934, 0x49dc, { 0x91, 0xa7, 0x6c, 0xcb, 0x80, 0xcc, 0x02, 0xe3 } +}; +const GUID FWPM_LAYER_IPFORWARD_V4_DISCARD = { + 0x9e9ea773, 0x2fae, 0x4210, { 0x8f, 0x17, 0x34, 0x12, 0x9e, 0xf3, 0x69, 0xeb } +}; +const GUID FWPM_LAYER_IPFORWARD_V6_DISCARD = { + 0x31524a5d, 0x1dfe, 0x472f, { 0xbb, 0x93, 0x51, 0x8e, 0xe9, 0x45, 0xd8, 0xa2 } +}; +const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD = { + 0xac4a9833, 0xf69d, 0x4648, { 0xb2, 0x61, 0x6d, 0xc8, 0x48, 0x35, 0xef, 0x39 } +}; +const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD = { + 0x2a6ff955, 0x3b2b, 0x49d2, { 0x98, 0x48, 0xad, 0x9d, 0x72, 0xdc, 0xaa, 0xb7 } +}; +const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD = { + 0xc5f10551, 0xbdb0, 0x43d7, { 0xa3, 0x13, 0x50, 0xe2, 0x11, 0xf4, 0xd6, 0x8a } +}; +const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD = { + 0xf433df69, 0xccbd, 0x482e, { 0xb9, 0xb2, 0x57, 0x16, 0x56, 0x58, 0xc3, 0xb3 } +}; + +/** + * Convert filter layer GUID to name + */ +static char* layer2name(GUID *guid) +{ + struct { + GUID guid; + char *name; + } map[] = { + { FWPM_LAYER_IPSEC_KM_DEMUX_V4, "IPsec KM demux v4" }, + { FWPM_LAYER_IPSEC_KM_DEMUX_V6, "IPsec KM demux v6" }, + { FWPM_LAYER_IPSEC_V4, "IPsec v4" }, + { FWPM_LAYER_IPSEC_V6, "IPsec v6" }, + { FWPM_LAYER_IKEEXT_V4, "IKE ext v4" }, + { FWPM_LAYER_IKEEXT_V6, "IKE ext v6" }, + { FWPM_LAYER_INBOUND_IPPACKET_V4, "inbound v4" }, + { FWPM_LAYER_INBOUND_IPPACKET_V4_DISCARD, "inbound v4 dsc" }, + { FWPM_LAYER_INBOUND_IPPACKET_V6, "inbound v6" }, + { FWPM_LAYER_INBOUND_IPPACKET_V6_DISCARD, "inbound v6 dsc" }, + { FWPM_LAYER_OUTBOUND_IPPACKET_V4, "outbound v4" }, + { FWPM_LAYER_OUTBOUND_IPPACKET_V4_DISCARD, "outbound v4 dsc" }, + { FWPM_LAYER_OUTBOUND_IPPACKET_V6, "outbound v6" }, + { FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD, "outbound v6 dsc" }, + { FWPM_LAYER_IPFORWARD_V4, "forward v4" }, + { FWPM_LAYER_IPFORWARD_V4_DISCARD, "forward v4 dsc" }, + { FWPM_LAYER_IPFORWARD_V6, "forward v6" }, + { FWPM_LAYER_IPFORWARD_V6_DISCARD, "forward v6 discard" }, + { FWPM_LAYER_INBOUND_TRANSPORT_V4, "inbound transport v4" }, + { FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD, "inbound transport v4 dsc" }, + { FWPM_LAYER_INBOUND_TRANSPORT_V6, "inbound transport v6" }, + { FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD, "inbound v6 transport dsc" }, + { FWPM_LAYER_OUTBOUND_TRANSPORT_V4, "outbound transport v4" }, + { FWPM_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD, "outbound transport v4 dsc" }, + { FWPM_LAYER_OUTBOUND_TRANSPORT_V6, "outbound transport v6" }, + { FWPM_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD, "outbound transport v6 dsc" }, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (memeq(&map[i].guid, guid, sizeof(GUID))) + { + return map[i].name; + } + } + return NULL; +} + +/** + * Convert filter callout GUID to name + */ +static char* callout2name(GUID *guid) +{ + struct { + GUID guid; + char *name; + } map[] = { + { FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4, "inbound transport v4" }, + { FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6, "inbound transport v6" }, + { FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4, "outbound transport v4" }, + { FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6, "outbound transport v6" }, + { FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4, "inbound tunnel v4" }, + { FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6, "inbound tunnel v6" }, + { FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4, "outbound tunnel v4" }, + { FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6, "outbound tunnel v6" }, + { FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4, "forward in tunnel v4" }, + { FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6, "forward in tunnel v6" }, + { FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4, "forward out tunnel v4" }, + { FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6, "forward out tunnel v6" }, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (memeq(&map[i].guid, guid, sizeof(GUID))) + { + return map[i].name; + } + } + return guid2string(guid); +} + +/** + * Print display data with description + */ +static void print_display_data(FWPM_DISPLAY_DATA0 *data) +{ + char buf[128]; + + buf[0] = '\0'; + if (data->name) + { + wcstombs(buf, data->name, sizeof(buf)); + } + printf("%s", buf); + if (data->description) + { + buf[0] = '\0'; + wcstombs(buf, data->description, sizeof(buf)); + if (strlen(buf)) + { + printf(" (%s)", buf); + } + } +} + +/** + * List installed firewall filters + */ +static bool list_filters(HANDLE engine) +{ + HANDLE handle; + UINT32 returned; + DWORD res; + FWPM_FILTER0 **entries; + char *layer; + int i; + + res = FwpmFilterCreateEnumHandle0(engine, NULL, &handle); + if (res != ERROR_SUCCESS) + { + fprintf(stderr, "FwpmFilterCreateEnumHandle0(): 0x%08x\n", res); + return FALSE; + } + + while (TRUE) + { + res = FwpmFilterEnum0(engine, handle, 1, &entries, &returned); + if (res != ERROR_SUCCESS) + { + fprintf(stderr, "FwpmFilterEnum0(): 0x%08x\n", res); + FwpmFilterDestroyEnumHandle0(engine, handle); + return FALSE; + } + if (returned == 0) + { + break; + } + + layer = layer2name(&entries[0]->layerKey); + if (layer) + { + printf("Filter ID %llu, '", entries[0]->filterId); + print_display_data(&entries[0]->displayData); + printf("'\n"); + printf(" %s, ", layer); + if (entries[0]->effectiveWeight.type == FWP_UINT64) + { + printf("weight %016llx, ", *entries[0]->effectiveWeight.uint64); + } + + switch (entries[0]->action.type) + { + case FWP_ACTION_BLOCK: + printf("block\n"); + break; + case FWP_ACTION_PERMIT: + printf("permit\n"); + break; + case FWP_ACTION_CALLOUT_TERMINATING: + printf("callout terminating: %s\n", + callout2name(&entries[0]->action.calloutKey)); + break; + case FWP_ACTION_CALLOUT_INSPECTION: + printf("callout inspection: %s\n", + callout2name(&entries[0]->action.calloutKey)); + break; + case FWP_ACTION_CALLOUT_UNKNOWN: + printf("callout unknown: %s\n", + callout2name(&entries[0]->action.calloutKey)); + break; + default: + printf("(unknown action)\n"); + break; + } + for (i = 0; i < entries[0]->numFilterConditions; i++) + { + list_cond(engine, &entries[0]->filterCondition[i]); + } + } + FwpmFreeMemory0((void**)&entries); + } + FwpmFilterDestroyEnumHandle0(engine, handle); + return TRUE; +} + +/** + * ipsecdump main() + */ +int main(int argc, char *argv[]) +{ + FWPM_SESSION0 session = { + .displayData = { + .name = L"ipsecdump", + .description = L"strongSwan SAD/SPD dumper", + }, + }; + HANDLE engine; + DWORD res; + int code; + + library_init(NULL, "ipsecdump"); + atexit(library_deinit); + + res = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engine); + if (res != ERROR_SUCCESS) + { + fprintf(stderr, "FwpmEngineOpen(): 0x%08x\n", res); + return 2; + } + if (argc > 1 && streq(argv[1], "filters")) + { + code = list_filters(engine) ? 0 : 1; + } + else + { + code = list_contexts(engine) ? 0 : 1; + } + FwpmEngineClose0(engine); + return code; +} diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c new file mode 100644 index 000000000..41f85ba5c --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <library.h> + +const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS = { + 0xb235ae9a, 0x1d64, 0x49b8, { 0xa4,0x4c,0x5f,0xf3,0xd9,0x09,0x50,0x45 } +}; +const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS = { + 0xd9ee00de, 0xc1ef, 0x4617, { 0xbf,0xe3,0xff,0xd8,0xf5,0xa0,0x89,0x57 } +}; +const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS = { + 0xae96897e, 0x2e94, 0x4bc9, { 0xb3,0x13,0xb2,0x7e,0xe8,0x0e,0x57,0x4d } +}; +const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS = { + 0x2d79133b, 0xb390, 0x45c6, { 0x86,0x99,0xac,0xac,0xea,0xaf,0xed,0x33 } +}; +const GUID FWPM_CONDITION_IP_LOCAL_PORT = { + 0x0c1ba1af, 0x5765, 0x453f, { 0xaf,0x22,0xa8,0xf7,0x91,0xac,0x77,0x5b } +}; +const GUID FWPM_CONDITION_IP_REMOTE_PORT = { + 0xc35a604d, 0xd22b, 0x4e1a, { 0x91,0xb4,0x68,0xf6,0x74,0xee,0x67,0x4b } +}; +const GUID FWPM_CONDITION_IP_PROTOCOL = { + 0x3971ef2b, 0x623e, 0x4f9a, { 0x8c,0xb1,0x6e,0x79,0xb8,0x06,0xb9,0xa7 } +}; +const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4 = { + 0x5926dfc8, 0xe3cf, 0x4426, { 0xa2,0x83,0xdc,0x39,0x3f,0x5d,0x0f,0x9d } +}; +const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6 = { + 0x634a869f, 0xfc23, 0x4b90, { 0xb0,0xc1,0xbf,0x62,0x0a,0x36,0xae,0x6f } +}; +const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4 = { + 0x09e61aea, 0xd214, 0x46e2, { 0x9b,0x21,0xb2,0x6b,0x0b,0x2f,0x28,0xc8 } +}; +const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6 = { + 0xe1735bde, 0x013f, 0x4655, { 0xb3,0x51,0xa4,0x9e,0x15,0x76,0x2d,0xf0 } +}; +const GUID FWPM_LAYER_IPFORWARD_V4 = { + 0xa82acc24, 0x4ee1, 0x4ee1, { 0xb4,0x65,0xfd,0x1d,0x25,0xcb,0x10,0xa4} +}; +const GUID FWPM_LAYER_IPFORWARD_V6 = { + 0x7b964818, 0x19c7, 0x493a, { 0xb7,0x1f,0x83,0x2c,0x36,0x84,0xd2,0x8c } +}; +const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 = { + 0x5132900d, 0x5e84, 0x4b5f, { 0x80,0xe4,0x01,0x74,0x1e,0x81,0xff,0x10 } +}; +const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6 = { + 0x49d3ac92, 0x2a6c, 0x4dcf, { 0x95,0x5f,0x1c,0x3b,0xe0,0x09,0xdd,0x99 } +}; +const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4 = { + 0x4b46bf0a, 0x4523, 0x4e57, { 0xaa,0x38,0xa8,0x79,0x87,0xc9,0x10,0xd9 } +}; +const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6 = { + 0x38d87722, 0xad83, 0x4f11, { 0xa9,0x1f,0xdf,0x0f,0xb0,0x77,0x22,0x5b } +}; +const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4 = { + 0x191a8a46, 0x0bf8, 0x46cf, { 0xb0,0x45,0x4b,0x45,0xdf,0xa6,0xa3,0x24 } +}; +const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6 = { + 0x80c342e3, 0x1e53, 0x4d6f, { 0x9b,0x44,0x03,0xdf,0x5a,0xee,0xe1,0x54 } +}; +const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4 = { + 0x70a4196c, 0x835b, 0x4fb0, { 0x98,0xe8,0x07,0x5f,0x4d,0x97,0x7d,0x46 } +}; +const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 = { + 0xf1835363, 0xa6a5, 0x4e62, { 0xb1,0x80,0x23,0xdb,0x78,0x9d,0x8d,0xa6 } +}; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 = { + 0x28829633, 0xc4f0, 0x4e66, { 0x87,0x3f,0x84,0x4d,0xb2,0xa8,0x99,0xc7 } +}; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 = { + 0xaf50bec2, 0xc686, 0x429a, { 0x88,0x4d,0xb7,0x44,0x43,0xe7,0xb0,0xb4 } +}; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 = { + 0xfb532136, 0x15cb, 0x440b, { 0x93,0x7c,0x17,0x17,0xca,0x32,0x0c,0x40 } +}; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 = { + 0xdae640cc, 0xe021, 0x4bee, { 0x9e,0xb6,0xa4,0x8b,0x27,0x5c,0x8c,0x1d } +}; + +/** + * Load a function symbol from a loaded dll + */ +static inline void *load_function(char *dll, char *name) +{ + HANDLE handle; + void *sym = NULL; + + handle = GetModuleHandle(dll); + if (!handle) + { + return NULL; + } + sym = GetProcAddress(handle, name); + return sym; +} + +/** + * Macro that defines a stub for a function that calls the same DLL function + * + * @param dll DLL to find function in + * @param ret return type of function + * @param name function name + * @param size size of all arguments on stack + * @param ... arguments of function + */ +#define STUB(dll, ret, name, size, ...) \ +ret WINAPI name(__VA_ARGS__) \ +{ \ + static void (*fun)() = NULL; \ + if (!fun) \ + { \ + fun = load_function(#dll, #name); \ + } \ + if (fun) \ + { \ + __builtin_return(__builtin_apply(fun, __builtin_apply_args(), size)); \ + } \ + return ERROR_NOT_SUPPORTED; \ +} + +STUB(fwpuclnt, DWORD, IPsecSaContextCreate1, 40, + HANDLE engineHandle, const void *outboundTraffic, + const void *virtualIfTunnelInfo, UINT64 *inboundFilterId, UINT64 *id) + +STUB(fwpuclnt, DWORD, IPsecSaContextSetSpi0, 32, + HANDLE engineHandle, UINT64 id, const void *getSpi, UINT32 inboundSpi) + +STUB(fwpuclnt, DWORD, IPsecSaContextGetById1, 24, + HANDLE engineHandle, UINT64 id, void **saContext) + +STUB(fwpuclnt, DWORD, IPsecSaContextUpdate0, 24, + HANDLE engineHandle, UINT32 flags, const void *newValues) + +STUB(fwpuclnt, DWORD, IPsecSaContextEnum1, 40, + HANDLE engineHandle, HANDLE enumHandle, UINT32 numEntriesRequested, + void ***entries, UINT32 *numEntriesReturned) + +STUB(fwpuclnt, DWORD, FwpmNetEventSubscribe0, 40, + HANDLE engineHandle, const void *subscription, void(*callback)(), + void *context, HANDLE *eventsHandle) + +STUB(fwpuclnt, DWORD, FwpmNetEventUnsubscribe0, 16, + HANDLE engineHandle, HANDLE eventsHandle) diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h new file mode 100644 index 000000000..50a89a007 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup kernel_wfp_compat kernel_wfp_compat + * @{ @ingroup kernel_wfp + */ + +#ifndef KERNEL_WFP_COMPAT_H_ +#define KERNEL_WFP_COMPAT_H_ + +#include <winsock2.h> +#include <windows.h> +#include <ipsectypes.h> + +/* MinGW defines CIPHERs incorrectly starting at 0 */ +#define IPSEC_CIPHER_TYPE_DES 1 +#define IPSEC_CIPHER_TYPE_3DES 2 +#define IPSEC_CIPHER_TYPE_AES_128 3 +#define IPSEC_CIPHER_TYPE_AES_192 4 +#define IPSEC_CIPHER_TYPE_AES_256 5 +#define IPSEC_CIPHER_TYPE_MAX 6 + +#include <fwpmtypes.h> +#include <fwpmu.h> +#undef interface + +/* MinGW defines TRANSFORMs incorrectly starting at 0 */ +#define IPSEC_TRANSFORM_AH 1 +#define IPSEC_TRANSFORM_ESP_AUTH 2 +#define IPSEC_TRANSFORM_ESP_CIPHER 3 +#define IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER 4 +#define IPSEC_TRANSFORM_ESP_AUTH_FW 5 +#define IPSEC_TRANSFORM_TYPE_MAX 6 + +/* missing in MinGW */ +enum { + FWPM_TUNNEL_FLAG_POINT_TO_POINT = (1<<0), + FWPM_TUNNEL_FLAG_ENABLE_VIRTUAL_IF_TUNNELING = (1<<1), +}; + +/* missing in MinGW */ +enum { + IPSEC_SA_DETAILS_UPDATE_TRAFFIC = (1<<0), + IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION = (1<<1), + IPSEC_SA_BUNDLE_UPDATE_FLAGS = (1<<2), + IPSEC_SA_BUNDLE_UPDATE_NAP_CONTEXT = (1<<3), + IPSEC_SA_BUNDLE_UPDATE_KEY_MODULE_STATE = (1<<4), + IPSEC_SA_BUNDLE_UPDATE_PEER_V4_PRIVATE_ADDRESS = (1<<5), + IPSEC_SA_BUNDLE_UPDATE_MM_SA_ID = (1<<6), +}; + +/* missing in MinGW */ +enum { + FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET = (1<<0), + FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET = (1<<1), + FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET = (1<<2), + FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET = (1<<3), + FWPM_NET_EVENT_FLAG_REMOTE_PORT_SET = (1<<4), + FWPM_NET_EVENT_FLAG_APP_ID_SET = (1<<5), + FWPM_NET_EVENT_FLAG_USER_ID_SET = (1<<6), + FWPM_NET_EVENT_FLAG_SCOPE_ID_SET = (1<<7), + FWPM_NET_EVENT_FLAG_IP_VERSION_SET = (1<<8), + FWPM_NET_EVENT_FLAG_REAUTH_REASON_SET = (1<<9), +}; + +/* missing in MinGW */ +enum { + FWPM_FILTER_FLAG_PERSISTENT = (1<<0), + FWPM_FILTER_FLAG_BOOTTIME = (1<<1), + FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT = (1<<2), + FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT = (1<<3), + FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED = (1<<4), + FWPM_FILTER_FLAG_DISABLED = (1<<5), +}; + +/* missing in MinGW */ +enum { + IPSEC_SA_BUNDLE_FLAG_ND_SECURE = (1<< 0), + IPSEC_SA_BUNDLE_FLAG_ND_BOUNDARY = (1<< 1), + IPSEC_SA_BUNDLE_FLAG_ND_PEER_NAT_BOUNDARY = (1<< 2), + IPSEC_SA_BUNDLE_FLAG_GUARANTEE_ENCRYPTION = (1<< 3), + IPSEC_SA_BUNDLE_FLAG_NLB = (1<< 4), + IPSEC_SA_BUNDLE_FLAG_NO_MACHINE_LUID_VERIFY = (1<< 5), + IPSEC_SA_BUNDLE_FLAG_NO_IMPERSONATION_LUID_VERIFY = (1<< 6), + IPSEC_SA_BUNDLE_FLAG_NO_EXPLICIT_CRED_MATCH = (1<< 7), + IPSEC_SA_BUNDLE_FLAG_ALLOW_NULL_TARGET_NAME_MATCH = (1<< 9), + IPSEC_SA_BUNDLE_FLAG_CLEAR_DF_ON_TUNNEL = (1<<10), + IPSEC_SA_BUNDLE_FLAG_ASSUME_UDP_CONTEXT_OUTBOUND = (1<<11), + IPSEC_SA_BUNDLE_FLAG_ND_PEER_BOUNDARY = (1<<12), + IPSEC_SA_BUNDLE_FLAG_SUPPRESS_DUPLICATE_DELETION = (1<<13), + IPSEC_SA_BUNDLE_FLAG_PEER_SUPPORTS_GUARANTEE_ENCRYPTION = (1<<14), + IPSEC_SA_BUNDLE_FLAG_FORCE_INBOUND_CONNECTIONS = (1<<15), + IPSEC_SA_BUNDLE_FLAG_FORCE_OUTBOUND_CONNECTIONS = (1<<16), + IPSEC_SA_BUNDLE_FLAG_FORWARD_PATH_INITIATOR = (1<<17), +}; + +/* missing in some MinGW versions */ +const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS; +const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS; +const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS; +const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS; +const GUID FWPM_CONDITION_IP_LOCAL_PORT; +const GUID FWPM_CONDITION_IP_REMOTE_PORT; +const GUID FWPM_CONDITION_IP_PROTOCOL; +#ifndef FWPM_CONDITION_ICMP_TYPE +# define FWPM_CONDITION_ICMP_TYPE FWPM_CONDITION_IP_LOCAL_PORT +#endif +#ifndef FWPM_CONDITION_ICMP_CODE +# define FWPM_CONDITION_ICMP_CODE FWPM_CONDITION_IP_REMOTE_PORT +#endif +const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4; +const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6; +const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4; +const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6; +const GUID FWPM_LAYER_IPFORWARD_V4; +const GUID FWPM_LAYER_IPFORWARD_V6; +const GUID FWPM_SUBLAYER_IPSEC_TUNNEL; +const GUID FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL; +const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4; +const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6; +const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4; +const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6; +const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4; +const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6; +const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4; +const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6; + +/* integrity config, missing in some MinGW versions */ +#ifndef IPSEC_AUTH_CONFIG_HMAC_MD5_96 +enum { + IPSEC_AUTH_CONFIG_HMAC_MD5_96 = 0, + IPSEC_AUTH_CONFIG_HMAC_SHA_1_96, + IPSEC_AUTH_CONFIG_HMAC_SHA_256_128, + IPSEC_AUTH_CONFIG_GCM_AES_128, + IPSEC_AUTH_CONFIG_GCM_AES_192, + IPSEC_AUTH_CONFIG_GCM_AES_256, + IPSEC_AUTH_CONFIG_MAX +}; +#define IPSEC_AUTH_TRANSFORM_ID_HMAC_MD5_96 { \ + IPSEC_AUTH_MD5, IPSEC_AUTH_CONFIG_HMAC_MD5_96 } +#define IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96 { \ + IPSEC_AUTH_SHA_1, IPSEC_AUTH_CONFIG_HMAC_SHA_1_96 } +#define IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_256_128 { \ + IPSEC_AUTH_SHA_256, IPSEC_AUTH_CONFIG_HMAC_SHA_256_128 } +#define IPSEC_AUTH_TRANSFORM_ID_GCM_AES_128 { \ + IPSEC_AUTH_AES_128, IPSEC_AUTH_CONFIG_GCM_AES_128 } +#define IPSEC_AUTH_TRANSFORM_ID_GCM_AES_192 { \ + IPSEC_AUTH_AES_192, IPSEC_AUTH_CONFIG_GCM_AES_192 } +#define IPSEC_AUTH_TRANSFORM_ID_GCM_AES_256 { \ + IPSEC_AUTH_AES_256, IPSEC_AUTH_CONFIG_GCM_AES_256 } +#endif + +/* encryption config, missing in some MinGW versions */ +#ifndef IPSEC_CIPHER_CONFIG_CBC_DES +enum { + IPSEC_CIPHER_CONFIG_CBC_DES = 1, + IPSEC_CIPHER_CONFIG_CBC_3DES, + IPSEC_CIPHER_CONFIG_CBC_AES_128, + IPSEC_CIPHER_CONFIG_CBC_AES_192, + IPSEC_CIPHER_CONFIG_CBC_AES_256, + IPSEC_CIPHER_CONFIG_GCM_AES_128, + IPSEC_CIPHER_CONFIG_GCM_AES_192, + IPSEC_CIPHER_CONFIG_GCM_AES_256, + IPSEC_CIPHER_CONFIG_MAX +}; +#define IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_128 { \ + IPSEC_CIPHER_TYPE_AES_128, IPSEC_CIPHER_CONFIG_GCM_AES_128 } +#define IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_192 { \ + IPSEC_CIPHER_TYPE_AES_192, IPSEC_CIPHER_CONFIG_GCM_AES_192 } +#define IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_256 { \ + IPSEC_CIPHER_TYPE_AES_256, IPSEC_CIPHER_CONFIG_GCM_AES_256 } +#define IPSEC_CIPHER_TRANSFORM_ID_CBC_DES { \ + IPSEC_CIPHER_TYPE_DES, IPSEC_CIPHER_CONFIG_CBC_DES } +#define IPSEC_CIPHER_TRANSFORM_ID_CBC_3DES { \ + IPSEC_CIPHER_TYPE_3DES, IPSEC_CIPHER_CONFIG_CBC_3DES } +#define IPSEC_CIPHER_TRANSFORM_ID_AES_128 { \ + IPSEC_CIPHER_TYPE_AES_128, IPSEC_CIPHER_CONFIG_CBC_AES_128 } +#define IPSEC_CIPHER_TRANSFORM_ID_AES_192 { \ + IPSEC_CIPHER_TYPE_AES_192, IPSEC_CIPHER_CONFIG_CBC_AES_192 } +#define IPSEC_CIPHER_TRANSFORM_ID_AES_256 { \ + IPSEC_CIPHER_TYPE_AES_256, IPSEC_CIPHER_CONFIG_CBC_AES_256 } +#endif + +DWORD WINAPI FwpmIPsecTunnelAdd0(HANDLE, UINT32, + const FWPM_PROVIDER_CONTEXT0*, const FWPM_PROVIDER_CONTEXT0*, UINT32, + const FWPM_FILTER_CONDITION0*, PSECURITY_DESCRIPTOR); + +#endif /** KERNEL_WFP_COMPAT_H_ @}*/ diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c new file mode 100644 index 000000000..c788bfb10 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c @@ -0,0 +1,2551 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* Windows 7, for some fwpmu.h functionality */ +#define _WIN32_WINNT 0x0601 + +#include "kernel_wfp_compat.h" +#include "kernel_wfp_ipsec.h" + +#include <daemon.h> +#include <hydra.h> +#include <threading/mutex.h> +#include <collections/array.h> +#include <collections/hashtable.h> +#include <processing/jobs/callback_job.h> + + +typedef struct private_kernel_wfp_ipsec_t private_kernel_wfp_ipsec_t; + +struct private_kernel_wfp_ipsec_t { + + /** + * Public interface + */ + kernel_wfp_ipsec_t public; + + /** + * Next SPI to allocate + */ + refcount_t nextspi; + + /** + * Mix value to distribute SPI allocation randomly + */ + u_int32_t mixspi; + + /** + * IKE bypass filters, as UINT64 filter LUID + */ + array_t *bypass; + + /** + * Temporary SAD/SPD entries referenced reqid, as uintptr_t => entry_t + */ + hashtable_t *tsas; + + /** + * SAD/SPD entries referenced by inbound SA, as sa_entry_t => entry_t + */ + hashtable_t *isas; + + /** + * SAD/SPD entries referenced by outbound SA, as sa_entry_t => entry_t + */ + hashtable_t *osas; + + /** + * Installed routes, as route_t => route_t + */ + hashtable_t *routes; + + /** + * Installed traps, as trap_t => trap_t + */ + hashtable_t *traps; + + /** + * Mutex for accessing entries + */ + mutex_t *mutex; + + /** + * WFP session handle + */ + HANDLE handle; + + /** + * Provider charon registers as + */ + FWPM_PROVIDER0 provider; + + /** + * Event handle + */ + HANDLE event; +}; + +/** + * Security association entry + */ +typedef struct { + /** SPI for this SA */ + u_int32_t spi; + /** protocol, IPPROTO_ESP/IPPROTO_AH */ + u_int8_t protocol; + /** hard lifetime of SA */ + u_int32_t lifetime; + /** destination host address for this SPI */ + host_t *dst; + struct { + /** algorithm */ + u_int16_t alg; + /** key */ + chunk_t key; + } integ, encr; +} sa_entry_t; + +/** + * Hash function for sas lookup table + */ +static u_int hash_sa(sa_entry_t *key) +{ + return chunk_hash_inc(chunk_from_thing(key->spi), + chunk_hash(key->dst->get_address(key->dst))); +} + +/** + * equals function for sas lookup table + */ +static bool equals_sa(sa_entry_t *a, sa_entry_t *b) +{ + return a->spi == b->spi && a->dst->ip_equals(a->dst, b->dst); +} + +/** + * Security policy entry + */ +typedef struct { + /** policy source addresses */ + traffic_selector_t *src; + /** policy destinaiton addresses */ + traffic_selector_t *dst; + /** WFP allocated LUID for inbound filter ID */ + u_int64_t policy_in; + /** WFP allocated LUID for outbound filter ID */ + u_int64_t policy_out; + /** WFP allocated LUID for forward inbound filter ID, tunnel mode only */ + u_int64_t policy_fwd_in; + /** WFP allocated LUID for forward outbound filter ID, tunnel mode only */ + u_int64_t policy_fwd_out; + /** have installed a route for it? */ + bool route; +} sp_entry_t; + +/** + * Destroy an SP entry + */ +static void sp_entry_destroy(sp_entry_t *sp) +{ + sp->src->destroy(sp->src); + sp->dst->destroy(sp->dst); + free(sp); +} + +/** + * Collection of SA/SP database entries for a reqid + */ +typedef struct { + /** reqid of entry */ + u_int32_t reqid; + /** outer address on local host */ + host_t *local; + /** outer address on remote host */ + host_t *remote; + /** inbound SA entry */ + sa_entry_t isa; + /** outbound SA entry */ + sa_entry_t osa; + /** associated (outbound) policies, as sp_entry_t* */ + array_t *sps; + /** IPsec mode, tunnel|transport */ + ipsec_mode_t mode; + /** UDP encapsulation */ + bool encap; + /** provider context, for tunnel mode only */ + u_int64_t provider; + /** WFP allocated LUID for SA context */ + u_int64_t sa_id; +} entry_t; + +/** + * Installed route + */ +typedef struct { + /** destination net of route */ + host_t *dst; + /** prefix length of dst */ + u_int8_t mask; + /** source address for route */ + host_t *src; + /** gateway of route, NULL if directly attached */ + host_t *gtw; + /** references for route */ + u_int refs; +} route_t; + +/** + * Destroy a route_t + */ +static void destroy_route(route_t *this) +{ + this->dst->destroy(this->dst); + this->src->destroy(this->src); + DESTROY_IF(this->gtw); + free(this); +} + +/** + * Hashtable equals function for routes + */ +static bool equals_route(route_t *a, route_t *b) +{ + return a->mask == b->mask && + a->dst->ip_equals(a->dst, b->dst) && + a->src->ip_equals(a->src, b->src); +} + +/** + * Hashtable hash function for routes + */ +static u_int hash_route(route_t *route) +{ + return chunk_hash_inc(route->src->get_address(route->src), + chunk_hash_inc(route->dst->get_address(route->dst), route->mask)); +} + +/** forward declaration */ +static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry, + bool add); + +/** + * Remove policies associated to an entry from kernel + */ +static void cleanup_policies(private_kernel_wfp_ipsec_t *this, entry_t *entry) +{ + enumerator_t *enumerator; + sp_entry_t *sp; + + if (entry->mode == MODE_TUNNEL) + { + manage_routes(this, entry, FALSE); + } + + enumerator = array_create_enumerator(entry->sps); + while (enumerator->enumerate(enumerator, &sp)) + { + if (sp->policy_in) + { + FwpmFilterDeleteById0(this->handle, sp->policy_in); + sp->policy_in = 0; + } + if (sp->policy_out) + { + FwpmFilterDeleteById0(this->handle, sp->policy_out); + sp->policy_out = 0; + } + if (sp->policy_fwd_in) + { + FwpmFilterDeleteById0(this->handle, sp->policy_fwd_in); + sp->policy_fwd_in = 0; + } + if (sp->policy_fwd_out) + { + FwpmFilterDeleteById0(this->handle, sp->policy_fwd_out); + sp->policy_fwd_out = 0; + } + } + enumerator->destroy(enumerator); +} + +/** + * Destroy a SA/SP entry set + */ +static void entry_destroy(private_kernel_wfp_ipsec_t *this, entry_t *entry) +{ + if (entry->sa_id) + { + IPsecSaContextDeleteById0(this->handle, entry->sa_id); + } + if (entry->provider) + { + FwpmProviderContextDeleteById0(this->handle, entry->provider); + } + cleanup_policies(this, entry); + array_destroy_function(entry->sps, (void*)sp_entry_destroy, NULL); + entry->local->destroy(entry->local); + entry->remote->destroy(entry->remote); + chunk_clear(&entry->isa.integ.key); + chunk_clear(&entry->isa.encr.key); + chunk_clear(&entry->osa.integ.key); + chunk_clear(&entry->osa.encr.key); + free(entry); +} + +/** + * Append/Realloc a filter condition to an existing condition set + */ +static FWPM_FILTER_CONDITION0 *append_condition(FWPM_FILTER_CONDITION0 *conds[], + int *count) +{ + FWPM_FILTER_CONDITION0 *cond; + + (*count)++; + *conds = realloc(*conds, *count * sizeof(*cond)); + cond = *conds + *count - 1; + memset(cond, 0, sizeof(*cond)); + + return cond; +} + +/** + * Convert an IPv4 prefix to a host order subnet mask + */ +static u_int32_t prefix2mask(u_int8_t prefix) +{ + u_int8_t netmask[4] = {}; + int i; + + for (i = 0; i < sizeof(netmask); i++) + { + if (prefix < 8) + { + netmask[i] = 0xFF << (8 - prefix); + break; + } + netmask[i] = 0xFF; + prefix -= 8; + } + return untoh32(netmask); +} + +/** + * Convert a 16-bit range to a WFP condition + */ +static void range2cond(FWPM_FILTER_CONDITION0 *cond, + u_int16_t from, u_int16_t to) +{ + if (from == to) + { + cond->matchType = FWP_MATCH_EQUAL; + cond->conditionValue.type = FWP_UINT16; + cond->conditionValue.uint16 = from; + } + else + { + cond->matchType = FWP_MATCH_RANGE; + cond->conditionValue.type = FWP_RANGE_TYPE; + cond->conditionValue.rangeValue = calloc(1, sizeof(FWP_RANGE0)); + cond->conditionValue.rangeValue->valueLow.type = FWP_UINT16; + cond->conditionValue.rangeValue->valueLow.uint16 = from; + cond->conditionValue.rangeValue->valueHigh.type = FWP_UINT16; + cond->conditionValue.rangeValue->valueHigh.uint16 = to; + } +} + +/** + * (Re-)allocate filter conditions for given local or remote traffic selector + */ +static bool ts2condition(traffic_selector_t *ts, const GUID *target, + FWPM_FILTER_CONDITION0 *conds[], int *count) +{ + FWPM_FILTER_CONDITION0 *cond; + FWP_BYTE_ARRAY16 *addr; + FWP_RANGE0 *range; + u_int16_t from_port, to_port; + void *from, *to; + u_int8_t proto; + host_t *net; + u_int8_t prefix; + + from = ts->get_from_address(ts).ptr; + to = ts->get_to_address(ts).ptr; + from_port = ts->get_from_port(ts); + to_port = ts->get_to_port(ts); + + cond = append_condition(conds, count); + cond->fieldKey = *target; + if (ts->is_host(ts, NULL)) + { + cond->matchType = FWP_MATCH_EQUAL; + switch (ts->get_type(ts)) + { + case TS_IPV4_ADDR_RANGE: + cond->conditionValue.type = FWP_UINT32; + cond->conditionValue.uint32 = untoh32(from); + break; + case TS_IPV6_ADDR_RANGE: + cond->conditionValue.type = FWP_BYTE_ARRAY16_TYPE; + cond->conditionValue.byteArray16 = addr = malloc(sizeof(*addr)); + memcpy(addr, from, sizeof(*addr)); + break; + default: + return FALSE; + } + } + else if (ts->to_subnet(ts, &net, &prefix)) + { + FWP_V6_ADDR_AND_MASK *m6; + FWP_V4_ADDR_AND_MASK *m4; + + cond->matchType = FWP_MATCH_EQUAL; + switch (net->get_family(net)) + { + case AF_INET: + cond->conditionValue.type = FWP_V4_ADDR_MASK; + cond->conditionValue.v4AddrMask = m4 = calloc(1, sizeof(*m4)); + m4->addr = untoh32(from); + m4->mask = prefix2mask(prefix); + break; + case AF_INET6: + cond->conditionValue.type = FWP_V6_ADDR_MASK; + cond->conditionValue.v6AddrMask = m6 = calloc(1, sizeof(*m6)); + memcpy(m6->addr, from, sizeof(m6->addr)); + m6->prefixLength = prefix; + break; + default: + net->destroy(net); + return FALSE; + } + net->destroy(net); + } + else + { + cond->matchType = FWP_MATCH_RANGE; + cond->conditionValue.type = FWP_RANGE_TYPE; + cond->conditionValue.rangeValue = range = calloc(1, sizeof(*range)); + switch (ts->get_type(ts)) + { + case TS_IPV4_ADDR_RANGE: + range->valueLow.type = FWP_UINT32; + range->valueLow.uint32 = untoh32(from); + range->valueHigh.type = FWP_UINT32; + range->valueHigh.uint32 = untoh32(to); + break; + case TS_IPV6_ADDR_RANGE: + range->valueLow.type = FWP_BYTE_ARRAY16_TYPE; + range->valueLow.byteArray16 = addr = malloc(sizeof(*addr)); + memcpy(addr, from, sizeof(*addr)); + range->valueHigh.type = FWP_BYTE_ARRAY16_TYPE; + range->valueHigh.byteArray16 = addr = malloc(sizeof(*addr)); + memcpy(addr, to, sizeof(*addr)); + break; + default: + return FALSE; + } + } + + proto = ts->get_protocol(ts); + if (proto && target == &FWPM_CONDITION_IP_LOCAL_ADDRESS) + { + cond = append_condition(conds, count); + cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL; + cond->matchType = FWP_MATCH_EQUAL; + cond->conditionValue.type = FWP_UINT8; + cond->conditionValue.uint8 = proto; + } + + if (proto == IPPROTO_ICMP) + { + if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS) + { + u_int8_t from_type, to_type, from_code, to_code; + + from_type = traffic_selector_icmp_type(from_port); + to_type = traffic_selector_icmp_type(to_port); + from_code = traffic_selector_icmp_code(from_port); + to_code = traffic_selector_icmp_code(to_port); + + if (from_type != 0 || to_type != 0xFF) + { + cond = append_condition(conds, count); + cond->fieldKey = FWPM_CONDITION_ICMP_TYPE; + range2cond(cond, from_type, to_type); + } + if (from_code != 0 || to_code != 0xFF) + { + cond = append_condition(conds, count); + cond->fieldKey = FWPM_CONDITION_ICMP_CODE; + range2cond(cond, from_code, to_code); + } + } + } + else if (from_port != 0 || to_port != 0xFFFF) + { + if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS) + { + cond = append_condition(conds, count); + cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT; + range2cond(cond, from_port, to_port); + } + if (target == &FWPM_CONDITION_IP_REMOTE_ADDRESS) + { + cond = append_condition(conds, count); + cond->fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; + range2cond(cond, from_port, to_port); + } + } + return TRUE; +} + +/** + * Free memory associated to a single condition + */ +static void free_condition(FWP_DATA_TYPE type, void *value) +{ + FWP_RANGE0 *range; + + switch (type) + { + case FWP_BYTE_ARRAY16_TYPE: + case FWP_V4_ADDR_MASK: + case FWP_V6_ADDR_MASK: + free(value); + break; + case FWP_RANGE_TYPE: + range = value; + free_condition(range->valueLow.type, range->valueLow.sd); + free_condition(range->valueHigh.type, range->valueHigh.sd); + free(range); + break; + default: + break; + } +} + +/** + * Free memory used by a set of conditions + */ +static void free_conditions(FWPM_FILTER_CONDITION0 *conds, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + free_condition(conds[i].conditionValue.type, conds[i].conditionValue.sd); + } + free(conds); +} + +/** + * Find the callout GUID for given parameters + */ +static bool find_callout(bool tunnel, bool v6, bool inbound, bool forward, + GUID *layer, GUID *sublayer, GUID *callout) +{ + struct { + bool tunnel; + bool v6; + bool inbound; + bool forward; + const GUID *layer; + const GUID *sublayer; + const GUID *callout; + } map[] = { + { 0, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4, NULL, + &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4 }, + { 0, 0, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4, NULL, + &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 }, + { 0, 1, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6, NULL, + &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6 }, + { 0, 1, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6, NULL, + &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6 }, + { 1, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4, + &FWPM_SUBLAYER_IPSEC_TUNNEL, + &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4 }, + { 1, 0, 0, 1, &FWPM_LAYER_IPFORWARD_V4, + &FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL, + &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 }, + { 1, 0, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4, + &FWPM_SUBLAYER_IPSEC_TUNNEL, + &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4 }, + { 1, 0, 1, 1, &FWPM_LAYER_IPFORWARD_V4, + &FWPM_SUBLAYER_IPSEC_TUNNEL, + &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 }, + { 1, 1, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6, + &FWPM_SUBLAYER_IPSEC_TUNNEL, + &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 }, + { 1, 1, 0, 1, &FWPM_LAYER_IPFORWARD_V6, + &FWPM_SUBLAYER_IPSEC_TUNNEL, + &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 }, + { 1, 1, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6, + &FWPM_SUBLAYER_IPSEC_TUNNEL, + &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6 }, + { 1, 1, 1, 1, &FWPM_LAYER_IPFORWARD_V6, + &FWPM_SUBLAYER_IPSEC_TUNNEL, + &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 }, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (tunnel == map[i].tunnel && + v6 == map[i].v6 && + inbound == map[i].inbound && + forward == map[i].forward) + { + *callout = *map[i].callout; + *layer = *map[i].layer; + if (map[i].sublayer) + { + *sublayer = *map[i].sublayer; + } + return TRUE; + } + } + return FALSE; +} + +/** + * Install a single policy in to the kernel + */ +static bool install_sp(private_kernel_wfp_ipsec_t *this, sp_entry_t *sp, + GUID *context, bool inbound, bool fwd, UINT64 *filter_id) +{ + FWPM_FILTER_CONDITION0 *conds = NULL; + traffic_selector_t *local, *remote; + const GUID *ltarget, *rtarget; + int count = 0; + bool v6; + DWORD res; + FWPM_FILTER0 filter = { + .displayData = { + .name = L"charon IPsec policy", + }, + .action = { + .type = FWP_ACTION_CALLOUT_TERMINATING, + }, + }; + + if (context) + { + filter.flags |= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT; + filter.providerKey = (GUID*)&this->provider.providerKey; + filter.providerContextKey = *context; + } + + v6 = sp->src->get_type(sp->src) == TS_IPV6_ADDR_RANGE; + if (!find_callout(context != NULL, v6, inbound, fwd, + &filter.layerKey, &filter.subLayerKey, + &filter.action.calloutKey)) + { + return FALSE; + } + + if (inbound && fwd) + { + local = sp->dst; + remote = sp->src; + } + else + { + local = sp->src; + remote = sp->dst; + } + if (fwd) + { + ltarget = &FWPM_CONDITION_IP_SOURCE_ADDRESS; + rtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS; + } + else + { + ltarget = &FWPM_CONDITION_IP_LOCAL_ADDRESS; + rtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS; + } + if (!ts2condition(local, ltarget, &conds, &count) || + !ts2condition(remote, rtarget, &conds, &count)) + { + free_conditions(conds, count); + return FALSE; + } + + filter.numFilterConditions = count; + filter.filterCondition = conds; + + res = FwpmFilterAdd0(this->handle, &filter, NULL, filter_id); + free_conditions(conds, count); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "installing %s%sbound WFP filter failed: 0x%08x", + fwd ? "forward " : "", inbound ? "in" : "out", res); + return FALSE; + } + return TRUE; +} + +/** + * Install a set of policies in to the kernel + */ +static bool install_sps(private_kernel_wfp_ipsec_t *this, + entry_t *entry, GUID *context) +{ + enumerator_t *enumerator; + sp_entry_t *sp; + + enumerator = array_create_enumerator(entry->sps); + while (enumerator->enumerate(enumerator, &sp)) + { + /* inbound policy */ + if (!install_sp(this, sp, context, TRUE, FALSE, &sp->policy_in)) + { + enumerator->destroy(enumerator); + return FALSE; + } + /* outbound policy */ + if (!install_sp(this, sp, context, FALSE, FALSE, &sp->policy_out)) + { + enumerator->destroy(enumerator); + return FALSE; + } + if (context) + { + if (!sp->src->is_host(sp->src, entry->local) || + !sp->dst->is_host(sp->dst, entry->remote)) + { + /* inbound forward policy, from decapsulation */ + if (!install_sp(this, sp, context, + TRUE, TRUE, &sp->policy_fwd_in)) + { + enumerator->destroy(enumerator); + return FALSE; + } + /* outbound forward policy, to encapsulate */ + if (!install_sp(this, sp, context, + FALSE, TRUE, &sp->policy_fwd_out)) + { + enumerator->destroy(enumerator); + return FALSE; + } + } + } + } + enumerator->destroy(enumerator); + + return TRUE; +} + +/** + * Convert a chunk_t to a WFP FWP_BYTE_BLOB + */ +static inline FWP_BYTE_BLOB chunk2blob(chunk_t chunk) +{ + return (FWP_BYTE_BLOB){ + .size = chunk.len, + .data = chunk.ptr, + }; +} + +/** + * Convert an integrity_algorithm_t to a WFP IPSEC_AUTH_TRANFORM_ID0 + */ +static bool alg2auth(integrity_algorithm_t alg, + IPSEC_SA_AUTH_INFORMATION0 *info) +{ + struct { + integrity_algorithm_t alg; + IPSEC_AUTH_TRANSFORM_ID0 transform; + } map[] = { + { AUTH_HMAC_MD5_96, IPSEC_AUTH_TRANSFORM_ID_HMAC_MD5_96 }, + { AUTH_HMAC_SHA1_96, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96 }, + { AUTH_HMAC_SHA2_256_128, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_256_128}, + { AUTH_AES_128_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_128 }, + { AUTH_AES_192_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_192 }, + { AUTH_AES_256_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_256 }, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (map[i].alg == alg) + { + info->authTransform.authTransformId = map[i].transform; + return TRUE; + } + } + return FALSE; +} + +/** + * Convert an encryption_algorithm_t to a WFP IPSEC_CIPHER_TRANFORM_ID0 + */ +static bool alg2cipher(encryption_algorithm_t alg, int keylen, + IPSEC_SA_CIPHER_INFORMATION0 *info) +{ + struct { + encryption_algorithm_t alg; + int keylen; + IPSEC_CIPHER_TRANSFORM_ID0 transform; + } map[] = { + { ENCR_DES, 8, IPSEC_CIPHER_TRANSFORM_ID_CBC_DES }, + { ENCR_3DES, 24, IPSEC_CIPHER_TRANSFORM_ID_CBC_3DES }, + { ENCR_AES_CBC, 16, IPSEC_CIPHER_TRANSFORM_ID_AES_128 }, + { ENCR_AES_CBC, 24, IPSEC_CIPHER_TRANSFORM_ID_AES_192 }, + { ENCR_AES_CBC, 32, IPSEC_CIPHER_TRANSFORM_ID_AES_256 }, + { ENCR_AES_GCM_ICV16, 20, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_128 }, + { ENCR_AES_GCM_ICV16, 28, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_192 }, + { ENCR_AES_GCM_ICV16, 36, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_256 }, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (map[i].alg == alg && map[i].keylen == keylen) + { + info->cipherTransform.cipherTransformId = map[i].transform; + return TRUE; + } + } + return FALSE; +} + +/** + * Get the integrity algorithm used for an AEAD transform + */ +static integrity_algorithm_t encr2integ(encryption_algorithm_t encr, int keylen) +{ + struct { + encryption_algorithm_t encr; + int keylen; + integrity_algorithm_t integ; + } map[] = { + { ENCR_NULL_AUTH_AES_GMAC, 20, AUTH_AES_128_GMAC }, + { ENCR_NULL_AUTH_AES_GMAC, 28, AUTH_AES_192_GMAC }, + { ENCR_NULL_AUTH_AES_GMAC, 36, AUTH_AES_256_GMAC }, + { ENCR_AES_GCM_ICV16, 20, AUTH_AES_128_GMAC }, + { ENCR_AES_GCM_ICV16, 28, AUTH_AES_192_GMAC }, + { ENCR_AES_GCM_ICV16, 36, AUTH_AES_256_GMAC }, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (map[i].encr == encr && map[i].keylen == keylen) + { + return map[i].integ; + } + } + return AUTH_UNDEFINED; +} + +/** + * Install a single SA + */ +static bool install_sa(private_kernel_wfp_ipsec_t *this, entry_t *entry, + bool inbound, sa_entry_t *sa, FWP_IP_VERSION version) +{ + IPSEC_SA_AUTH_AND_CIPHER_INFORMATION0 info = {}; + IPSEC_SA0 ipsec = { + .spi = ntohl(sa->spi), + }; + IPSEC_SA_BUNDLE0 bundle = { + .lifetime = { + .lifetimeSeconds = inbound ? entry->isa.lifetime + : entry->osa.lifetime, + }, + .saList = &ipsec, + .numSAs = 1, + .ipVersion = version, + }; + struct { + u_int16_t alg; + chunk_t key; + } integ = {}, encr = {}; + DWORD res; + + switch (sa->protocol) + { + case IPPROTO_AH: + ipsec.saTransformType = IPSEC_TRANSFORM_AH; + ipsec.ahInformation = &info.saAuthInformation; + integ.key = sa->integ.key; + integ.alg = sa->integ.alg; + break; + case IPPROTO_ESP: + if (sa->encr.alg == ENCR_NULL || + sa->encr.alg == ENCR_NULL_AUTH_AES_GMAC) + { + ipsec.saTransformType = IPSEC_TRANSFORM_ESP_AUTH; + ipsec.espAuthInformation = &info.saAuthInformation; + } + else + { + ipsec.saTransformType = IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER; + ipsec.espAuthAndCipherInformation = &info; + encr.key = sa->encr.key; + encr.alg = sa->encr.alg; + } + if (encryption_algorithm_is_aead(sa->encr.alg)) + { + integ.alg = encr2integ(sa->encr.alg, sa->encr.key.len); + integ.key = sa->encr.key; + } + else + { + integ.alg = sa->integ.alg; + integ.key = sa->integ.key; + } + break; + default: + return FALSE; + } + + if (integ.alg) + { + info.saAuthInformation.authKey = chunk2blob(integ.key); + if (!alg2auth(integ.alg, &info.saAuthInformation)) + { + DBG1(DBG_KNL, "integrity algorithm %N not supported by WFP", + integrity_algorithm_names, integ.alg); + return FALSE; + } + } + if (encr.alg) + { + info.saCipherInformation.cipherKey = chunk2blob(encr.key); + if (!alg2cipher(encr.alg, encr.key.len, &info.saCipherInformation)) + { + DBG1(DBG_KNL, "encryption algorithm %N not supported by WFP", + encryption_algorithm_names, encr.alg); + return FALSE; + } + } + + if (inbound) + { + res = IPsecSaContextAddInbound0(this->handle, entry->sa_id, &bundle); + } + else + { + bundle.flags |= IPSEC_SA_BUNDLE_FLAG_ASSUME_UDP_CONTEXT_OUTBOUND; + res = IPsecSaContextAddOutbound0(this->handle, entry->sa_id, &bundle); + } + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "adding %sbound WFP SA failed: 0x%08x", + inbound ? "in" : "out", res); + return FALSE; + } + return TRUE; +} + +/** + * Convert an IPv6 host address to WFP representation + */ +static void host2address6(host_t *host, void *out) +{ + u_int32_t *src, *dst = out; + + src = (u_int32_t*)host->get_address(host).ptr; + + dst[0] = untoh32(&src[3]); + dst[1] = untoh32(&src[2]); + dst[2] = untoh32(&src[1]); + dst[3] = untoh32(&src[0]); +} + +/** + * Fill in traffic structure from entry addresses + */ +static bool hosts2traffic(private_kernel_wfp_ipsec_t *this, + host_t *l, host_t *r, IPSEC_TRAFFIC1 *traffic) +{ + if (l->get_family(l) != r->get_family(r)) + { + return FALSE; + } + switch (l->get_family(l)) + { + case AF_INET: + traffic->ipVersion = FWP_IP_VERSION_V4; + traffic->localV4Address = untoh32(l->get_address(l).ptr); + traffic->remoteV4Address = untoh32(r->get_address(r).ptr); + return TRUE; + case AF_INET6: + traffic->ipVersion = FWP_IP_VERSION_V6; + host2address6(l, &traffic->localV6Address); + host2address6(r, &traffic->remoteV6Address); + return TRUE; + default: + return FALSE; + } +} + +/** + * Install SAs to the kernel + */ +static bool install_sas(private_kernel_wfp_ipsec_t *this, entry_t *entry, + IPSEC_TRAFFIC_TYPE type) +{ + IPSEC_TRAFFIC1 traffic = { + .trafficType = type, + }; + IPSEC_GETSPI1 spi = { + .inboundIpsecTraffic = { + .trafficType = type, + }, + }; + enumerator_t *enumerator; + sp_entry_t *sp; + DWORD res; + + if (type == IPSEC_TRAFFIC_TYPE_TRANSPORT) + { + enumerator = array_create_enumerator(entry->sps); + if (enumerator->enumerate(enumerator, &sp)) + { + traffic.ipsecFilterId = sp->policy_out; + spi.inboundIpsecTraffic.ipsecFilterId = sp->policy_in; + } + else + { + enumerator->destroy(enumerator); + return FALSE; + } + enumerator->destroy(enumerator); + } + else + { + traffic.tunnelPolicyId = entry->provider; + spi.inboundIpsecTraffic.tunnelPolicyId = entry->provider; + } + + if (!hosts2traffic(this, entry->local, entry->remote, &traffic)) + { + return FALSE; + } + + res = IPsecSaContextCreate1(this->handle, &traffic, NULL, NULL, + &entry->sa_id); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "creating WFP SA context failed: 0x%08x", res); + return FALSE; + } + + memcpy(spi.inboundIpsecTraffic.localV6Address, traffic.localV6Address, + sizeof(traffic.localV6Address)); + memcpy(spi.inboundIpsecTraffic.remoteV6Address, traffic.remoteV6Address, + sizeof(traffic.remoteV6Address)); + spi.ipVersion = traffic.ipVersion; + + res = IPsecSaContextSetSpi0(this->handle, entry->sa_id, &spi, + ntohl(entry->isa.spi)); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "setting WFP SA SPI failed: 0x%08x", res); + IPsecSaContextDeleteById0(this->handle, entry->sa_id); + entry->sa_id = 0; + return FALSE; + } + + if (!install_sa(this, entry, TRUE, &entry->isa, spi.ipVersion) || + !install_sa(this, entry, FALSE, &entry->osa, spi.ipVersion)) + { + IPsecSaContextDeleteById0(this->handle, entry->sa_id); + entry->sa_id = 0; + return FALSE; + } + + if (entry->encap) + { + IPSEC_V4_UDP_ENCAPSULATION0 encap = { + .localUdpEncapPort = entry->local->get_port(entry->local), + .remoteUdpEncapPort = entry->remote->get_port(entry->remote), + }; + IPSEC_SA_CONTEXT1 *ctx; + + res = IPsecSaContextGetById1(this->handle, entry->sa_id, &ctx); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "getting WFP SA for UDP encap failed: 0x%08x", res); + IPsecSaContextDeleteById0(this->handle, entry->sa_id); + entry->sa_id = 0; + return FALSE; + } + ctx->inboundSa->udpEncapsulation = &encap; + ctx->outboundSa->udpEncapsulation = &encap; + + res = IPsecSaContextUpdate0(this->handle, + IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION, ctx); + FwpmFreeMemory0((void**)&ctx); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "enable WFP UDP encap failed: 0x%08x", res); + IPsecSaContextDeleteById0(this->handle, entry->sa_id); + entry->sa_id = 0; + return FALSE; + } + } + + return TRUE; +} + +/** + * Install a transport mode SA/SP set to the kernel + */ +static bool install_transport(private_kernel_wfp_ipsec_t *this, entry_t *entry) +{ + if (install_sps(this, entry, NULL) && + install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT)) + { + return TRUE; + } + cleanup_policies(this, entry); + return FALSE; +} + +/** + * Generate a new GUID, random + */ +static bool generate_guid(private_kernel_wfp_ipsec_t *this, GUID *guid) +{ + bool ok; + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + return FALSE; + } + ok = rng->get_bytes(rng, sizeof(GUID), (u_int8_t*)guid); + rng->destroy(rng); + return ok; +} + +/** + * Register a dummy tunnel provider to associate tunnel filters to + */ +static bool add_tunnel_provider(private_kernel_wfp_ipsec_t *this, + entry_t *entry, GUID *guid, UINT64 *luid) +{ + DWORD res; + + IPSEC_AUTH_TRANSFORM0 transform = { + /* Create any valid proposal. This is actually not used, as we + * don't create an SA from this information. */ + .authTransformId = IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96, + }; + IPSEC_SA_TRANSFORM0 transforms = { + .ipsecTransformType = IPSEC_TRANSFORM_ESP_AUTH, + .espAuthTransform = &transform, + }; + IPSEC_PROPOSAL0 proposal = { + .lifetime = { + /* We need a valid lifetime, even if we don't create any SA + * from these values. Pick some values accepted. */ + .lifetimeSeconds = 0xFFFF, + .lifetimeKilobytes = 0xFFFFFFFF, + .lifetimePackets = 0xFFFFFFFF, + }, + .numSaTransforms = 1, + .saTransforms = &transforms, + }; + IPSEC_TUNNEL_POLICY0 policy = { + .numIpsecProposals = 1, + .ipsecProposals = &proposal, + .saIdleTimeout = { + /* not used, set to lifetime for maximum */ + .idleTimeoutSeconds = proposal.lifetime.lifetimeSeconds, + .idleTimeoutSecondsFailOver = proposal.lifetime.lifetimeSeconds, + }, + }; + FWPM_PROVIDER_CONTEXT0 qm = { + .displayData = { + .name = L"charon tunnel provider", + }, + .providerKey = (GUID*)&this->provider.providerKey, + .type = FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT, + .ikeQmTunnelPolicy = &policy, + }; + + switch (entry->local->get_family(entry->local)) + { + case AF_INET: + policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V4; + policy.tunnelEndpoints.localV4Address = + untoh32(entry->local->get_address(entry->local).ptr); + policy.tunnelEndpoints.remoteV4Address = + untoh32(entry->remote->get_address(entry->remote).ptr); + break; + case AF_INET6: + policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V6; + host2address6(entry->local, &policy.tunnelEndpoints.localV6Address); + host2address6(entry->remote, &policy.tunnelEndpoints.remoteV6Address); + break; + default: + return FALSE; + } + + if (!generate_guid(this, &qm.providerContextKey)) + { + return FALSE; + } + + res = FwpmProviderContextAdd0(this->handle, &qm, NULL, luid); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "adding provider context failed: 0x%08x", res); + return FALSE; + } + *guid = qm.providerContextKey; + return TRUE; +} + +/** + * Install tunnel mode SPs to the kernel + */ +static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) +{ + GUID guid; + + if (!add_tunnel_provider(this, entry, &guid, &entry->provider)) + { + return FALSE; + } + if (!install_sps(this, entry, &guid)) + { + return FALSE; + } + return TRUE; +} + +/** + * Reduce refcount, or uninstall a route if all refs gone + */ +static bool uninstall_route(private_kernel_wfp_ipsec_t *this, + host_t *dst, u_int8_t mask, host_t *src, host_t *gtw) +{ + route_t *route, key = { + .dst = dst, + .mask = mask, + .src = src, + }; + char *name; + bool res = FALSE; + + this->mutex->lock(this->mutex); + route = this->routes->get(this->routes, &key); + if (route) + { + if (--route->refs == 0) + { + if (hydra->kernel_interface->get_interface(hydra->kernel_interface, + src, &name)) + { + res = hydra->kernel_interface->del_route(hydra->kernel_interface, + dst->get_address(dst), mask, gtw, src, name) == SUCCESS; + free(name); + } + route = this->routes->remove(this->routes, route); + if (route) + { + destroy_route(route); + } + } + else + { + res = TRUE; + } + } + this->mutex->unlock(this->mutex); + + return res; +} + +/** + * Install a single route, or refcount if exists + */ +static bool install_route(private_kernel_wfp_ipsec_t *this, + host_t *dst, u_int8_t mask, host_t *src, host_t *gtw) +{ + route_t *route, key = { + .dst = dst, + .mask = mask, + .src = src, + }; + char *name; + bool res = FALSE; + + this->mutex->lock(this->mutex); + route = this->routes->get(this->routes, &key); + if (route) + { + route->refs++; + res = TRUE; + } + else + { + if (hydra->kernel_interface->get_interface(hydra->kernel_interface, + src, &name)) + { + if (hydra->kernel_interface->add_route(hydra->kernel_interface, + dst->get_address(dst), mask, gtw, src, name) == SUCCESS) + { + INIT(route, + .dst = dst->clone(dst), + .mask = mask, + .src = src->clone(src), + .gtw = gtw ? gtw->clone(gtw) : NULL, + .refs = 1, + ); + route = this->routes->put(this->routes, route, route); + if (route) + { + destroy_route(route); + } + res = TRUE; + } + free(name); + } + } + this->mutex->unlock(this->mutex); + + return res; +} + +/** + * (Un)-install a single route + */ +static bool manage_route(private_kernel_wfp_ipsec_t *this, + host_t *local, host_t *remote, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + bool add) +{ + host_t *src, *dst, *gtw; + u_int8_t mask; + bool done; + + if (!dst_ts->to_subnet(dst_ts, &dst, &mask)) + { + return FALSE; + } + if (hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface, + src_ts, &src, NULL) != SUCCESS) + { + dst->destroy(dst); + return FALSE; + } + gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface, + remote, -1, local); + if (add) + { + done = install_route(this, dst, mask, src, gtw); + } + else + { + done = uninstall_route(this, dst, mask, src, gtw); + } + dst->destroy(dst); + src->destroy(src); + DESTROY_IF(gtw); + + if (!done) + { + DBG1(DBG_KNL, "%sinstalling route for policy %R === %R failed", + add ? "" : "un", src_ts, dst_ts); + } + return done; +} + +/** + * (Un)-install routes for IPsec policies + */ +static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry, + bool add) +{ + enumerator_t *enumerator; + sp_entry_t *sp; + + enumerator = array_create_enumerator(entry->sps); + while (enumerator->enumerate(enumerator, &sp)) + { + if (add && sp->route) + { + continue; + } + if (!add && !sp->route) + { + continue; + } + if (manage_route(this, entry->local, entry->remote, + sp->src, sp->dst, add)) + { + sp->route = add; + } + } + enumerator->destroy(enumerator); + + return TRUE; +} + +/** + * Install a tunnel mode SA/SP set to the kernel + */ +static bool install_tunnel(private_kernel_wfp_ipsec_t *this, entry_t *entry) +{ + if (install_tunnel_sps(this, entry) && + manage_routes(this, entry, TRUE) && + install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TUNNEL)) + { + return TRUE; + } + cleanup_policies(this, entry); + return FALSE; +} + +/** + * Install a SA/SP set to the kernel + */ +static bool install(private_kernel_wfp_ipsec_t *this, entry_t *entry) +{ + switch (entry->mode) + { + case MODE_TRANSPORT: + return install_transport(this, entry); + case MODE_TUNNEL: + return install_tunnel(this, entry); + case MODE_BEET: + default: + return FALSE; + } +} + +/** + * Installed trap entry + */ +typedef struct { + /** reqid this trap is installed for */ + u_int32_t reqid; + /** is this a forward policy trap for tunnel mode? */ + bool fwd; + /** do we have installed a route for this trap policy? */ + bool route; + /** local address of associated route */ + host_t *local; + /** remote address of associated route */ + host_t *remote; + /** src traffic selector */ + traffic_selector_t *src; + /** dst traffic selector */ + traffic_selector_t *dst; + /** LUID of installed tunnel policy filter */ + UINT64 filter_id; +} trap_t; + +/** + * Destroy a trap entry + */ +static void destroy_trap(trap_t *this) +{ + this->local->destroy(this->local); + this->remote->destroy(this->remote); + this->src->destroy(this->src); + this->dst->destroy(this->dst); + free(this); +} + +/** + * Hashtable equals function for traps + */ +static bool equals_trap(trap_t *a, trap_t *b) +{ + return a->filter_id == b->filter_id; +} + +/** + * Hashtable hash function for traps + */ +static u_int hash_trap(trap_t *trap) +{ + return chunk_hash(chunk_from_thing(trap->filter_id)); +} + +/** + * Send an acquire for an installed trap filter + */ +static void acquire(private_kernel_wfp_ipsec_t *this, UINT64 filter_id, + traffic_selector_t *src, traffic_selector_t *dst) +{ + u_int32_t reqid = 0; + trap_t *trap, key = { + .filter_id = filter_id, + }; + + this->mutex->lock(this->mutex); + trap = this->traps->get(this->traps, &key); + if (trap) + { + reqid = trap->reqid; + } + this->mutex->unlock(this->mutex); + + if (reqid) + { + src = src ? src->clone(src) : NULL; + dst = dst ? dst->clone(dst) : NULL; + hydra->kernel_interface->acquire(hydra->kernel_interface, reqid, + src, dst); + } +} + +/** + * Create a single host traffic selector from an FWP address definition + */ +static traffic_selector_t *addr2ts(FWP_IP_VERSION version, void *data, + u_int8_t protocol, u_int16_t from_port, u_int16_t to_port) +{ + ts_type_t type; + UINT32 ints[4]; + chunk_t addr; + + switch (version) + { + case FWP_IP_VERSION_V4: + ints[0] = untoh32(data); + addr = chunk_from_thing(ints[0]); + type = TS_IPV4_ADDR_RANGE; + break; + case FWP_IP_VERSION_V6: + ints[3] = untoh32(data); + ints[2] = untoh32(data + 4); + ints[1] = untoh32(data + 8); + ints[0] = untoh32(data + 12); + addr = chunk_from_thing(ints); + type = TS_IPV6_ADDR_RANGE; + break; + default: + return NULL; + } + return traffic_selector_create_from_bytes(protocol, type, addr, from_port, + addr, to_port); +} + +/** + * FwpmNetEventSubscribe0() callback + */ +static void WINAPI event_callback(void *user, const FWPM_NET_EVENT1 *event) +{ + private_kernel_wfp_ipsec_t *this = user; + traffic_selector_t *local = NULL, *remote = NULL; + u_int8_t protocol = 0; + u_int16_t from_local = 0, to_local = 65535; + u_int16_t from_remote = 0, to_remote = 65535; + + if ((event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET) && + (event->header.flags & FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET)) + { + if (event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET) + { + from_local = to_local = event->header.localPort; + } + if (event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET) + { + from_remote = to_remote = event->header.remotePort; + } + if (event->header.flags & FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET) + { + protocol = event->header.ipProtocol; + } + + local = addr2ts(event->header.ipVersion, + (void*)&event->header.localAddrV6, + protocol, from_local, to_local); + remote = addr2ts(event->header.ipVersion, + (void*)&event->header.remoteAddrV6, + protocol, from_remote, to_remote); + } + + switch (event->type) + { + case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP: + acquire(this, event->classifyDrop->filterId, local, remote); + break; + case FWPM_NET_EVENT_TYPE_IKEEXT_MM_FAILURE: + case FWPM_NET_EVENT_TYPE_IKEEXT_QM_FAILURE: + case FWPM_NET_EVENT_TYPE_IKEEXT_EM_FAILURE: + case FWPM_NET_EVENT_TYPE_IPSEC_KERNEL_DROP: + DBG1(DBG_KNL, "IPsec kernel drop: %R === %R, error 0x%08x, " + "SPI 0x%08x, %s filterId %llu", local, remote, + event->ipsecDrop->failureStatus, event->ipsecDrop->spi, + event->ipsecDrop->direction ? "in" : "out", + event->ipsecDrop->filterId); + break; + case FWPM_NET_EVENT_TYPE_IPSEC_DOSP_DROP: + default: + break; + } + + DESTROY_IF(local); + DESTROY_IF(remote); +} + +/** + * Register for net events + */ +static bool register_events(private_kernel_wfp_ipsec_t *this) +{ + FWPM_NET_EVENT_SUBSCRIPTION0 subscription = {}; + DWORD res; + + res = FwpmNetEventSubscribe0(this->handle, &subscription, + event_callback, this, &this->event); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "registering for WFP events failed: 0x%08x", res); + return FALSE; + } + return TRUE; +} + +/** + * Install a trap policy to kernel + */ +static bool install_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap) +{ + FWPM_FILTER_CONDITION0 *conds = NULL; + int count = 0; + DWORD res; + const GUID *starget, *dtarget; + UINT64 weight = 0x000000000000ff00; + FWPM_FILTER0 filter = { + .displayData = { + .name = L"charon IPsec trap", + }, + .action = { + .type = FWP_ACTION_BLOCK, + }, + .weight = { + .type = FWP_UINT64, + .uint64 = &weight, + }, + }; + + if (trap->fwd) + { + if (trap->src->get_type(trap->src) == TS_IPV4_ADDR_RANGE) + { + filter.layerKey = FWPM_LAYER_IPFORWARD_V4; + } + else + { + filter.layerKey = FWPM_LAYER_IPFORWARD_V6; + } + starget = &FWPM_CONDITION_IP_SOURCE_ADDRESS; + dtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS; + } + else + { + if (trap->src->get_type(trap->src) == TS_IPV4_ADDR_RANGE) + { + filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V4; + } + else + { + filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V6; + } + starget = &FWPM_CONDITION_IP_LOCAL_ADDRESS; + dtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS; + } + + if (!ts2condition(trap->src, starget, &conds, &count) || + !ts2condition(trap->dst, dtarget, &conds, &count)) + { + free_conditions(conds, count); + return FALSE; + } + + filter.numFilterConditions = count; + filter.filterCondition = conds; + + res = FwpmFilterAdd0(this->handle, &filter, NULL, &trap->filter_id); + free_conditions(conds, count); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "installing WFP trap filter failed: 0x%08x", res); + return FALSE; + } + return TRUE; +} + +/** + * Uninstall a trap policy from kernel + */ +static bool uninstall_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap) +{ + DWORD res; + + res = FwpmFilterDeleteById0(this->handle, trap->filter_id); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "uninstalling WFP trap filter failed: 0x%08x", res); + return FALSE; + } + return TRUE; +} + +/** + * Create and install a new trap entry + */ +static bool add_trap(private_kernel_wfp_ipsec_t *this, + u_int32_t reqid, bool fwd, host_t *local, host_t *remote, + traffic_selector_t *src, traffic_selector_t *dst) +{ + trap_t *trap; + + INIT(trap, + .reqid = reqid, + .fwd = fwd, + .src = src->clone(src), + .dst = dst->clone(dst), + .local = local->clone(local), + .remote = remote->clone(remote), + ); + + if (!install_trap(this, trap)) + { + destroy_trap(trap); + return FALSE; + } + + trap->route = manage_route(this, local, remote, src, dst, TRUE); + + this->mutex->lock(this->mutex); + this->traps->put(this->traps, trap, trap); + this->mutex->unlock(this->mutex); + return TRUE; +} + +/** + * Uninstall and remove a new trap entry + */ +static bool remove_trap(private_kernel_wfp_ipsec_t *this, + u_int32_t reqid, bool fwd, + traffic_selector_t *src, traffic_selector_t *dst) +{ + enumerator_t *enumerator; + trap_t *trap, *found = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, NULL, &trap)) + { + if (reqid == trap->reqid && + fwd == trap->fwd && + src->equals(src, trap->src) && + dst->equals(dst, trap->dst)) + { + this->traps->remove_at(this->traps, enumerator); + found = trap; + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + if (found) + { + if (trap->route) + { + trap->route = !manage_route(this, trap->local, trap->remote, + src, dst, FALSE); + } + uninstall_trap(this, found); + destroy_trap(found); + return TRUE; + } + return FALSE; +} + +METHOD(kernel_ipsec_t, get_features, kernel_feature_t, + private_kernel_wfp_ipsec_t *this) +{ + return KERNEL_ESP_V3_TFC | KERNEL_NO_POLICY_UPDATES; +} + +/** + * Initialize seeds for SPI generation + */ +static bool init_spi(private_kernel_wfp_ipsec_t *this) +{ + bool ok = TRUE; + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + if (!rng) + { + return FALSE; + } + ok = rng->get_bytes(rng, sizeof(this->nextspi), (u_int8_t*)&this->nextspi); + if (ok) + { + ok = rng->get_bytes(rng, sizeof(this->mixspi), (u_int8_t*)&this->mixspi); + } + rng->destroy(rng); + return ok; +} + +/** + * Map an integer x with a one-to-one function using quadratic residues. + */ +static u_int permute(u_int x, u_int p) +{ + u_int qr; + + x = x % p; + qr = ((u_int64_t)x * x) % p; + if (x <= p / 2) + { + return qr; + } + return p - qr; +} + +METHOD(kernel_ipsec_t, get_spi, status_t, + private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, u_int32_t *spi) +{ + /* To avoid sequencial SPIs, we use a one-to-one permuation function on + * an incrementing counter, that is a full period PRNG for the range we + * allocate SPIs in. We add some randomness using a fixed XOR and start + * the counter at random position. This is not cryptographically safe, + * but that is actually not required. + * The selected prime should be smaller than the range we allocate SPIs + * in, and it must satisfy p % 4 == 3 to map x > p/2 using p - qr. */ + static const u_int p = 268435399, offset = 0xc0000000; + + *spi = htonl(offset + permute(ref_get(&this->nextspi) ^ this->mixspi, p)); + return SUCCESS; +} + +METHOD(kernel_ipsec_t, get_cpi, status_t, + private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t reqid, u_int16_t *cpi) +{ + return NOT_SUPPORTED; +} + +/** + * Data for an expire callback job + */ +typedef struct { + /* backref to kernel backend */ + private_kernel_wfp_ipsec_t *this; + /* SPI of expiring SA */ + u_int32_t spi; + /* destination address of expiring SA */ + host_t *dst; + /* is this a hard expire, or a rekey request? */ + bool hard; +} expire_data_t; + +/** + * Clean up expire data + */ +static void expire_data_destroy(expire_data_t *data) +{ + data->dst->destroy(data->dst); + free(data); +} + +/** + * Callback job for SA expiration + */ +static job_requeue_t expire_job(expire_data_t *data) +{ + private_kernel_wfp_ipsec_t *this = data->this; + u_int32_t reqid = 0; + u_int8_t protocol; + entry_t *entry; + sa_entry_t key = { + .spi = data->spi, + .dst = data->dst, + }; + + if (data->hard) + { + this->mutex->lock(this->mutex); + entry = this->isas->remove(this->isas, &key); + this->mutex->unlock(this->mutex); + if (entry) + { + protocol = entry->isa.protocol; + reqid = entry->reqid; + if (entry->osa.dst) + { + key.dst = entry->osa.dst; + key.spi = entry->osa.spi; + this->osas->remove(this->osas, &key); + } + entry_destroy(this, entry); + } + } + else + { + this->mutex->lock(this->mutex); + entry = this->isas->get(this->isas, &key); + if (entry) + { + protocol = entry->isa.protocol; + reqid = entry->reqid; + } + this->mutex->unlock(this->mutex); + } + + if (reqid) + { + hydra->kernel_interface->expire(hydra->kernel_interface, + reqid, protocol, data->spi, data->hard); + } + + return JOB_REQUEUE_NONE; +} + +/** + * Schedule an expire event for an SA + */ +static void schedule_expire(private_kernel_wfp_ipsec_t *this, u_int32_t spi, + host_t *dst, u_int32_t lifetime, bool hard) +{ + expire_data_t *data; + + INIT(data, + .this = this, + .spi = spi, + .dst = dst->clone(dst), + .hard = hard, + ); + + lib->scheduler->schedule_job(lib->scheduler, (job_t*) + callback_job_create((void*)expire_job, data, + (void*)expire_data_destroy, NULL), + lifetime); +} + +METHOD(kernel_ipsec_t, add_sa, status_t, + private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark, + u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, + u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window, + bool initiator, bool encap, bool esn, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts) +{ + host_t *local, *remote; + entry_t *entry; + + if (inbound) + { + /* comes first, create new entry */ + local = dst->clone(dst); + remote = src->clone(src); + + INIT(entry, + .reqid = reqid, + .isa = { + .spi = spi, + .dst = local, + .protocol = protocol, + .lifetime = lifetime->time.life, + .encr = { + .alg = enc_alg, + .key = chunk_clone(enc_key), + }, + .integ = { + .alg = int_alg, + .key = chunk_clone(int_key), + }, + }, + .sps = array_create(0, 0), + .local = local, + .remote = remote, + .mode = mode, + .encap = encap, + ); + + if (lifetime->time.life) + { + schedule_expire(this, spi, local, lifetime->time.life, TRUE); + } + if (lifetime->time.rekey && lifetime->time.rekey != lifetime->time.life) + { + schedule_expire(this, spi, local, lifetime->time.rekey, FALSE); + } + + this->mutex->lock(this->mutex); + this->tsas->put(this->tsas, (void*)(uintptr_t)reqid, entry); + this->isas->put(this->isas, &entry->isa, entry); + this->mutex->unlock(this->mutex); + } + else + { + /* comes after inbound, update entry */ + this->mutex->lock(this->mutex); + entry = this->tsas->remove(this->tsas, (void*)(uintptr_t)reqid); + this->mutex->unlock(this->mutex); + + if (!entry) + { + DBG1(DBG_KNL, "adding outbound SA failed, no inbound SA found " + "for reqid %u ", reqid); + return NOT_FOUND; + } + /* TODO: should we check for local/remote, mode etc.? */ + + entry->osa = (sa_entry_t){ + .spi = spi, + .dst = entry->remote, + .protocol = protocol, + .lifetime = lifetime->time.life, + .encr = { + .alg = enc_alg, + .key = chunk_clone(enc_key), + }, + .integ = { + .alg = int_alg, + .key = chunk_clone(int_key), + }, + }; + + this->mutex->lock(this->mutex); + this->osas->put(this->osas, &entry->osa, entry); + this->mutex->unlock(this->mutex); + } + + return SUCCESS; +} + +METHOD(kernel_ipsec_t, update_sa, status_t, + private_kernel_wfp_ipsec_t *this, u_int32_t spi, u_int8_t protocol, + u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, + bool encap, bool new_encap, mark_t mark) +{ + entry_t *entry; + sa_entry_t key = { + .dst = dst, + .spi = spi, + }; + UINT64 sa_id = 0; + IPSEC_SA_CONTEXT1 *ctx; + IPSEC_V4_UDP_ENCAPSULATION0 ports; + UINT32 flags = IPSEC_SA_DETAILS_UPDATE_TRAFFIC; + DWORD res; + + this->mutex->lock(this->mutex); + entry = this->osas->get(this->osas, &key); + this->mutex->unlock(this->mutex); + + if (entry) + { + /* outbound entry, nothing to do */ + return SUCCESS; + } + + this->mutex->lock(this->mutex); + entry = this->isas->get(this->isas, &key); + if (entry) + { + /* inbound entry, do update */ + sa_id = entry->sa_id; + ports.localUdpEncapPort = entry->local->get_port(entry->local); + ports.remoteUdpEncapPort = entry->remote->get_port(entry->remote); + } + this->mutex->unlock(this->mutex); + + if (!sa_id) + { + return NOT_FOUND; + } + + res = IPsecSaContextGetById1(this->handle, sa_id, &ctx); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "getting WFP SA context for updated failed: 0x%08x", res); + return FAILED; + } + if (!hosts2traffic(this, new_dst, new_src, &ctx->inboundSa->traffic) || + !hosts2traffic(this, new_dst, new_src, &ctx->outboundSa->traffic)) + { + FwpmFreeMemory0((void**)&ctx); + return FAILED; + } + + if (new_encap != encap) + { + if (new_encap) + { + ctx->inboundSa->udpEncapsulation = &ports; + ctx->outboundSa->udpEncapsulation = &ports; + } + else + { + ctx->inboundSa->udpEncapsulation = NULL; + ctx->outboundSa->udpEncapsulation = NULL; + } + flags |= IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION; + } + + res = IPsecSaContextUpdate0(this->handle, flags, ctx); + FwpmFreeMemory0((void**)&ctx); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "updating WFP SA context failed: 0x%08x", res); + return FAILED; + } + + this->mutex->lock(this->mutex); + entry = this->isas->remove(this->isas, &key); + if (entry) + { + key.spi = entry->osa.spi; + key.dst = entry->osa.dst; + this->osas->remove(this->osas, &key); + + entry->local->destroy(entry->local); + entry->remote->destroy(entry->remote); + entry->local = new_dst->clone(new_dst); + entry->remote = new_src->clone(new_src); + entry->isa.dst = entry->local; + entry->osa.dst = entry->remote; + + this->isas->put(this->isas, &entry->isa, entry); + this->osas->put(this->osas, &entry->osa, entry); + + manage_routes(this, entry, FALSE); + manage_routes(this, entry, TRUE); + } + this->mutex->unlock(this->mutex); + + return SUCCESS; +} + +METHOD(kernel_ipsec_t, query_sa, status_t, + private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes, + u_int64_t *packets, time_t *time) +{ + /* It does not seem that WFP provides any means of getting per-SA traffic + * statistics. IPsecGetStatistics0/1() provides global stats, and + * IPsecSaContextEnum0/1() and IPsecSaEnum0/1() return the configured + * values only. */ + return NOT_SUPPORTED; +} + +METHOD(kernel_ipsec_t, del_sa, status_t, + private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark) +{ + entry_t *entry; + sa_entry_t key = { + .dst = dst, + .spi = spi, + }; + + this->mutex->lock(this->mutex); + entry = this->isas->remove(this->isas, &key); + this->mutex->unlock(this->mutex); + + if (entry) + { + /* keep entry until removal of outbound */ + return SUCCESS; + } + + this->mutex->lock(this->mutex); + entry = this->osas->remove(this->osas, &key); + this->mutex->unlock(this->mutex); + + if (entry) + { + entry_destroy(this, entry); + return SUCCESS; + } + + return NOT_FOUND; +} + +METHOD(kernel_ipsec_t, flush_sas, status_t, + private_kernel_wfp_ipsec_t *this) +{ + return NOT_SUPPORTED; +} + +METHOD(kernel_ipsec_t, add_policy, status_t, + private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark, + policy_priority_t priority) +{ + status_t status = SUCCESS; + entry_t *entry; + sp_entry_t *sp; + sa_entry_t key = { + .spi = sa->esp.use ? sa->esp.spi : sa->ah.spi, + .dst = dst, + }; + + if (sa->esp.use && sa->ah.use) + { + return NOT_SUPPORTED; + } + + switch (type) + { + case POLICY_IPSEC: + break; + case POLICY_PASS: + case POLICY_DROP: + return NOT_SUPPORTED; + } + + switch (direction) + { + case POLICY_OUT: + break; + case POLICY_IN: + case POLICY_FWD: + /* not required */ + return SUCCESS; + default: + return NOT_SUPPORTED; + } + + switch (priority) + { + case POLICY_PRIORITY_DEFAULT: + break; + case POLICY_PRIORITY_ROUTED: + if (!add_trap(this, sa->reqid, FALSE, src, dst, src_ts, dst_ts)) + { + return FAILED; + } + if (sa->mode == MODE_TUNNEL) + { + if (!add_trap(this, sa->reqid, TRUE, src, dst, src_ts, dst_ts)) + { + return FAILED; + } + } + return SUCCESS; + case POLICY_PRIORITY_FALLBACK: + default: + return NOT_SUPPORTED; + } + + this->mutex->lock(this->mutex); + entry = this->osas->get(this->osas, &key); + if (entry) + { + if (sa->mode == MODE_TUNNEL || array_count(entry->sps) == 0) + { + INIT(sp, + .src = src_ts->clone(src_ts), + .dst = dst_ts->clone(dst_ts), + ); + array_insert(entry->sps, -1, sp); + if (array_count(entry->sps) == sa->policy_count) + { + if (!install(this, entry)) + { + status = FAILED; + } + } + } + else + { + /* TODO: reinstall with a filter using multiple TS? + * Filters are ANDed for a match, but we could install a filter + * with the inverse TS set using NOT-matches... */ + DBG1(DBG_KNL, "multiple transport mode traffic selectors not " + "supported by WFP"); + status = NOT_SUPPORTED; + } + } + else + { + DBG1(DBG_KNL, "adding SP failed, no SA found for SPI 0x%08x", key.spi); + status = FAILED; + } + this->mutex->unlock(this->mutex); + + return status; +} + +METHOD(kernel_ipsec_t, query_policy, status_t, + private_kernel_wfp_ipsec_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, + time_t *use_time) +{ + /* see query_sa() for some notes */ + return NOT_SUPPORTED; +} + +METHOD(kernel_ipsec_t, del_policy, status_t, + private_kernel_wfp_ipsec_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, + mark_t mark, policy_priority_t priority) +{ + if (direction == POLICY_OUT && priority == POLICY_PRIORITY_ROUTED) + { + if (remove_trap(this, reqid, FALSE, src_ts, dst_ts)) + { + remove_trap(this, reqid, TRUE, src_ts, dst_ts); + return SUCCESS; + } + return NOT_FOUND; + } + /* not required, as we delete the whole SA/SP set during del_sa() */ + return SUCCESS; +} + +METHOD(kernel_ipsec_t, flush_policies, status_t, + private_kernel_wfp_ipsec_t *this) +{ + return NOT_SUPPORTED; +} + +/** + * Add a bypass policy for a specific UDP port + */ +static bool add_bypass(private_kernel_wfp_ipsec_t *this, + int family, u_int16_t port, bool inbound, UINT64 *luid) +{ + FWPM_FILTER_CONDITION0 *cond, *conds = NULL; + int count = 0; + DWORD res; + UINT64 weight = 0xff00000000000000; + FWPM_FILTER0 filter = { + .displayData = { + .name = L"charon IKE bypass", + }, + .action = { + .type = FWP_ACTION_PERMIT, + }, + .weight = { + .type = FWP_UINT64, + .uint64 = &weight, + }, + }; + + switch (family) + { + case AF_INET: + filter.layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V4 + : FWPM_LAYER_OUTBOUND_TRANSPORT_V4; + break; + case AF_INET6: + filter.layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V6 + : FWPM_LAYER_OUTBOUND_TRANSPORT_V6; + break; + default: + return FALSE; + } + + cond = append_condition(&conds, &count); + cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL; + cond->matchType = FWP_MATCH_EQUAL; + cond->conditionValue.type = FWP_UINT8; + cond->conditionValue.uint8 = IPPROTO_UDP; + + cond = append_condition(&conds, &count); + cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT; + cond->matchType = FWP_MATCH_EQUAL; + cond->conditionValue.type = FWP_UINT16; + cond->conditionValue.uint16 = port; + + filter.numFilterConditions = count; + filter.filterCondition = conds; + + res = FwpmFilterAdd0(this->handle, &filter, NULL, luid); + free_conditions(conds, count); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "installing WFP bypass filter failed: 0x%08x", res); + return FALSE; + } + return TRUE; +} + +METHOD(kernel_ipsec_t, bypass_socket, bool, + private_kernel_wfp_ipsec_t *this, int fd, int family) +{ + union { + struct sockaddr sa; + SOCKADDR_IN in; + SOCKADDR_IN6 in6; + } saddr; + int addrlen = sizeof(saddr); + UINT64 filter_out, filter_in = 0; + u_int16_t port; + + if (getsockname(fd, &saddr.sa, &addrlen) == SOCKET_ERROR) + { + return FALSE; + } + switch (family) + { + case AF_INET: + port = ntohs(saddr.in.sin_port); + break; + case AF_INET6: + port = ntohs(saddr.in6.sin6_port); + break; + default: + return FALSE; + } + + if (!add_bypass(this, family, port, TRUE, &filter_in) || + !add_bypass(this, family, port, FALSE, &filter_out)) + { + if (filter_in) + { + FwpmFilterDeleteById0(this->handle, filter_in); + } + return FALSE; + } + + this->mutex->lock(this->mutex); + array_insert(this->bypass, ARRAY_TAIL, &filter_in); + array_insert(this->bypass, ARRAY_TAIL, &filter_out); + this->mutex->unlock(this->mutex); + + return TRUE; +} + +METHOD(kernel_ipsec_t, enable_udp_decap, bool, + private_kernel_wfp_ipsec_t *this, int fd, int family, u_int16_t port) +{ + return FALSE; +} + +METHOD(kernel_ipsec_t, destroy, void, + private_kernel_wfp_ipsec_t *this) +{ + UINT64 filter; + + while (array_remove(this->bypass, ARRAY_TAIL, &filter)) + { + FwpmFilterDeleteById0(this->handle, filter); + } + if (this->handle) + { + if (this->event) + { + FwpmNetEventUnsubscribe0(this->handle, this->event); + } + FwpmProviderDeleteByKey0(this->handle, &this->provider.providerKey); + FwpmEngineClose0(this->handle); + } + array_destroy(this->bypass); + this->tsas->destroy(this->tsas); + this->isas->destroy(this->isas); + this->osas->destroy(this->osas); + this->routes->destroy(this->routes); + this->traps->destroy(this->traps); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * Described in header. + */ +kernel_wfp_ipsec_t *kernel_wfp_ipsec_create() +{ + private_kernel_wfp_ipsec_t *this; + DWORD res; + FWPM_SESSION0 session = { + .displayData = { + .name = L"charon", + .description = L"strongSwan IKE kernel-wfp backend", + }, + }; + + INIT(this, + .public = { + .interface = { + .get_features = _get_features, + .get_spi = _get_spi, + .get_cpi = _get_cpi, + .add_sa = _add_sa, + .update_sa = _update_sa, + .query_sa = _query_sa, + .del_sa = _del_sa, + .flush_sas = _flush_sas, + .add_policy = _add_policy, + .query_policy = _query_policy, + .del_policy = _del_policy, + .flush_policies = _flush_policies, + .bypass_socket = _bypass_socket, + .enable_udp_decap = _enable_udp_decap, + .destroy = _destroy, + }, + }, + .provider = { + .displayData = { + .name = L"charon", + .description = L"strongSwan IKE kernel-wfp backend", + }, + .providerKey = { 0x59cdae2e, 0xf6bb, 0x4c09, + { 0xa9,0x59,0x9d,0x91,0xac,0xaf,0xf9,0x19 }}, + }, + .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), + .bypass = array_create(sizeof(UINT64), 2), + .tsas = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4), + .isas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4), + .osas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4), + .routes = hashtable_create((void*)hash_route, (void*)equals_route, 4), + .traps = hashtable_create((void*)hash_trap, (void*)equals_trap, 4), + ); + + if (!init_spi(this)) + { + destroy(this); + return NULL; + } + + res = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, + &this->handle); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "opening WFP engine failed: 0x%08x", res); + destroy(this); + return NULL; + } + + res = FwpmProviderAdd0(this->handle, &this->provider, NULL); + if (res != ERROR_SUCCESS && res != FWP_E_ALREADY_EXISTS) + { + DBG1(DBG_KNL, "registering WFP provider failed: 0x%08x", res); + destroy(this); + return NULL; + } + + if (!register_events(this)) + { + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.h b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.h new file mode 100644 index 000000000..d61c230e4 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup kernel_wfp_ipsec kernel_wfp_ipsec + * @{ @ingroup kernel_wfp + */ + +#ifndef KERNEL_WFP_IPSEC_H_ +#define KERNEL_WFP_IPSEC_H_ + +#include <library.h> +#include <kernel/kernel_ipsec.h> + +typedef struct kernel_wfp_ipsec_t kernel_wfp_ipsec_t; + +/** + * Windows Filter Platform based IPsec kernel backend. + */ +struct kernel_wfp_ipsec_t { + + /** + * Implements kernel_ipsec_t interface + */ + kernel_ipsec_t interface; +}; + +/** + * Create WFP kernel interface instance. + * + * @return kernel_wfp_ipsec_t instance + */ +kernel_wfp_ipsec_t *kernel_wfp_ipsec_create(); + +#endif /** KERNEL_WFP_IPSEC_H_ @}*/ diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_plugin.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_plugin.c new file mode 100644 index 000000000..e465b0a76 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_plugin.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "kernel_wfp_plugin.h" +#include "kernel_wfp_ipsec.h" + +#include <daemon.h> + +typedef struct private_kernel_wfp_plugin_t private_kernel_wfp_plugin_t; + +/** + * Private data of kernel-wfp plugin + */ +struct private_kernel_wfp_plugin_t { + + /** + * Implements plugin interface + */ + kernel_wfp_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_kernel_wfp_plugin_t *this) +{ + return "kernel-wfp"; +} + +METHOD(plugin_t, get_features, int, + private_kernel_wfp_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(kernel_ipsec_register, kernel_wfp_ipsec_create), + PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"), + PLUGIN_DEPENDS(RNG, RNG_WEAK), + PLUGIN_DEPENDS(RNG, RNG_STRONG), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_kernel_wfp_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *kernel_wfp_plugin_create() +{ + private_kernel_wfp_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_plugin.h b/src/libcharon/plugins/kernel_wfp/kernel_wfp_plugin.h new file mode 100644 index 000000000..a538e34a1 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_plugin.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup kernel_wfp kernel_wfp + * @ingroup cplugins + * + * @defgroup kernel_wfp_plugin kernel_wfp_plugin + * @{ @ingroup kernel_wfp + */ + +#ifndef KERNEL_WFP_PLUGIN_H_ +#define KERNEL_WFP_PLUGIN_H_ + +#include <library.h> +#include <plugins/plugin.h> + +typedef struct kernel_wfp_plugin_t kernel_wfp_plugin_t; + +/** + * Windows Filter Platform based IPsec backend plugin. + */ +struct kernel_wfp_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** KERNEL_WFP_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/kernel_wfp/mingw-w64-4.8.1.diff b/src/libcharon/plugins/kernel_wfp/mingw-w64-4.8.1.diff new file mode 100644 index 000000000..c72b94c07 --- /dev/null +++ b/src/libcharon/plugins/kernel_wfp/mingw-w64-4.8.1.diff @@ -0,0 +1,26 @@ +diff -Naur /mingw-orig/x86_64-w64-mingw32/include/fwptypes.h /mingw/x86_64-w64-mingw32/include/fwptypes.h +--- /mingw-orig/x86_64-w64-mingw32/include/fwptypes.h 2013-08-30 07:15:40 +0200 ++++ /mingw/x86_64-w64-mingw32/include/fwptypes.h 2014-01-02 16:32:26 +0100 +@@ -333,11 +333,6 @@ + } __C89_NAMELESSUNIONNAME; + } FWP_CONDITION_VALUE0; + +-typedef struct FWPM_DISPLAY_DATA0_ { +- wchar_t *name; +- wchar_t *description; +-} FWPM_DISPLAY_DATA0; +- + #endif /* WINAPI_PARTITION_DESKTOP. */ + /* Begin additional prototypes for all interfaces */ + +diff -Naur /mingw-orig/x86_64-w64-mingw32/include/iketypes.h /mingw/x86_64-w64-mingw32/include/iketypes.h +--- /mingw-orig/x86_64-w64-mingw32/include/iketypes.h 2013-08-30 07:15:40 +0200 ++++ /mingw/x86_64-w64-mingw32/include/iketypes.h 2014-01-02 16:31:12 +0100 +@@ -212,7 +212,6 @@ + FWP_BYTE_BLOB presharedKey; + UINT32 flags; + } IKEEXT_PRESHARED_KEY_AUTHENTICATION1; +-#endif + + typedef struct IKEEXT_CERTIFICATE_AUTHENTICATION0_ { + IKEEXT_CERT_CONFIG_TYPE inboundConfigType; diff --git a/src/libcharon/plugins/led/Makefile.am b/src/libcharon/plugins/led/Makefile.am index fbe779dd6..18d6af399 100644 --- a/src/libcharon/plugins/led/Makefile.am +++ b/src/libcharon/plugins/led/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-led.la diff --git a/src/libcharon/plugins/led/Makefile.in b/src/libcharon/plugins/led/Makefile.in index f7179cfe8..78ec6660e 100644 --- a/src/libcharon/plugins/led/Makefile.in +++ b/src/libcharon/plugins/led/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -263,6 +263,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -281,6 +282,7 @@ 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@ @@ -308,6 +310,7 @@ 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@ @@ -399,6 +402,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -415,7 +419,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-led.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-led.la diff --git a/src/libcharon/plugins/load_tester/Makefile.am b/src/libcharon/plugins/load_tester/Makefile.am index e7c08783f..31e1b5c6f 100644 --- a/src/libcharon/plugins/load_tester/Makefile.am +++ b/src/libcharon/plugins/load_tester/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-load-tester.la diff --git a/src/libcharon/plugins/load_tester/Makefile.in b/src/libcharon/plugins/load_tester/Makefile.in index 561d69a23..df75c0f4b 100644 --- a/src/libcharon/plugins/load_tester/Makefile.in +++ b/src/libcharon/plugins/load_tester/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -276,6 +276,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -294,6 +295,7 @@ 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@ @@ -321,6 +323,7 @@ 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@ @@ -412,6 +415,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -429,7 +433,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-load-tester.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-load-tester.la diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index e133190b4..bc7c0ffbc 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -150,7 +150,7 @@ struct private_load_tester_config_t { /** * incremental numbering of generated configs */ - u_int num; + refcount_t num; /** * Dynamic source port, if used @@ -802,7 +802,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, { if (streq(name, "load-test")) { - return generate_config(this, this->num++); + return generate_config(this, (u_int)ref_get(&this->num)); } return NULL; } diff --git a/src/libcharon/plugins/load_tester/load_tester_creds.c b/src/libcharon/plugins/load_tester/load_tester_creds.c index f17d41f46..d62c7295d 100644 --- a/src/libcharon/plugins/load_tester/load_tester_creds.c +++ b/src/libcharon/plugins/load_tester/load_tester_creds.c @@ -68,6 +68,11 @@ struct private_load_tester_creds_t { * Password for EAP */ shared_key_t *pwd; + + /** + * List of certificate distribution points to include in generated certs + */ + linked_list_t *cdps; }; /** @@ -377,6 +382,7 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, BUILD_NOT_BEFORE_TIME, now - 60 * 60 * 24, BUILD_NOT_AFTER_TIME, now + 60 * 60 * 24, BUILD_SERIAL, chunk_from_thing(serial), + BUILD_CRL_DISTRIBUTION_POINTS, this->cdps, BUILD_END); peer_key->destroy(peer_key); sans->destroy(sans); @@ -436,13 +442,14 @@ METHOD(load_tester_creds_t, destroy, void, DESTROY_IF(this->ca); this->psk->destroy(this->psk); this->pwd->destroy(this->pwd); + this->cdps->destroy_function(this->cdps, free); free(this); } load_tester_creds_t *load_tester_creds_create() { private_load_tester_creds_t *this; - char *pwd, *psk, *digest; + char *pwd, *psk, *digest, *crl; psk = lib->settings->get_str(lib->settings, "%s.plugins.load-tester.preshared_key", default_psk, lib->ns); @@ -450,6 +457,8 @@ load_tester_creds_t *load_tester_creds_create() "%s.plugins.load-tester.eap_password", default_pwd, lib->ns); digest = lib->settings->get_str(lib->settings, "%s.plugins.load-tester.digest", "sha1", lib->ns); + crl = lib->settings->get_str(lib->settings, + "%s.plugins.load-tester.crl", NULL, lib->ns); INIT(this, .public = { @@ -465,7 +474,7 @@ load_tester_creds_t *load_tester_creds_create() .private = load_issuer_key(), .ca = load_issuer_cert(), .cas = linked_list_create(), - .digest = enum_from_name(hash_algorithm_short_names, digest), + .cdps = linked_list_create(), .psk = shared_key_create(SHARED_IKE, chunk_clone(chunk_create(psk, strlen(psk)))), .pwd = shared_key_create(SHARED_EAP, @@ -477,14 +486,23 @@ load_tester_creds_t *load_tester_creds_create() this->cas->insert_last(this->cas, this->ca->get_ref(this->ca)); } - if (this->digest == -1) + if (!enum_from_name(hash_algorithm_short_names, digest, &this->digest)) { DBG1(DBG_CFG, "invalid load-tester digest: '%s', using sha1", digest); this->digest = HASH_SHA1; } + if (crl) + { + x509_cdp_t *cdp; + + INIT(cdp, + .uri = crl, + ); + this->cdps->insert_last(this->cdps, cdp); + } + load_ca_certs(this); return &this->public; } - diff --git a/src/libcharon/plugins/load_tester/load_tester_ipsec.c b/src/libcharon/plugins/load_tester/load_tester_ipsec.c index 02b1d4216..3f256ddd0 100644 --- a/src/libcharon/plugins/load_tester/load_tester_ipsec.c +++ b/src/libcharon/plugins/load_tester/load_tester_ipsec.c @@ -31,14 +31,14 @@ struct private_load_tester_ipsec_t { /** * faked SPI counter */ - u_int32_t spi; + refcount_t spi; }; METHOD(kernel_ipsec_t, get_spi, status_t, private_load_tester_ipsec_t *this, host_t *src, host_t *dst, u_int8_t protocol, u_int32_t reqid, u_int32_t *spi) { - *spi = ++this->spi; + *spi = (uint32_t)ref_get(&this->spi); return SUCCESS; } @@ -53,8 +53,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t, private_load_tester_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, - u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, - u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound, + u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, + u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window, + bool initiator, bool encap, bool esn, bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts) { return SUCCESS; diff --git a/src/libcharon/plugins/lookip/Makefile.am b/src/libcharon/plugins/lookip/Makefile.am index 6d71c8c13..223654ea9 100644 --- a/src/libcharon/plugins/lookip/Makefile.am +++ b/src/libcharon/plugins/lookip/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-lookip.la diff --git a/src/libcharon/plugins/lookip/Makefile.in b/src/libcharon/plugins/lookip/Makefile.in index 57aaeeaeb..deb517ed8 100644 --- a/src/libcharon/plugins/lookip/Makefile.in +++ b/src/libcharon/plugins/lookip/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -272,6 +272,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -290,6 +291,7 @@ 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@ @@ -317,6 +319,7 @@ 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@ @@ -408,6 +411,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -425,7 +429,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-lookip.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-lookip.la diff --git a/src/libcharon/plugins/maemo/Makefile.am b/src/libcharon/plugins/maemo/Makefile.am index c3c55ba41..fe5c963fd 100644 --- a/src/libcharon/plugins/maemo/Makefile.am +++ b/src/libcharon/plugins/maemo/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ ${maemo_CFLAGS} \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-maemo.la diff --git a/src/libcharon/plugins/maemo/Makefile.in b/src/libcharon/plugins/maemo/Makefile.in index e1d4ee301..aa3ade079 100644 --- a/src/libcharon/plugins/maemo/Makefile.in +++ b/src/libcharon/plugins/maemo/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -268,6 +268,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -286,6 +287,7 @@ 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@ @@ -313,6 +315,7 @@ 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@ @@ -404,6 +407,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -421,7 +425,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ ${maemo_CFLAGS} \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-maemo.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-maemo.la diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index f0f3105c4..2e96f8fb4 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -327,6 +327,7 @@ static gboolean initiate_connection(private_maemo_service_t *this, charon->socket->get_port(charon->socket, FALSE), hostname, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); peer_cfg = peer_cfg_create(this->current, ike_cfg, CERT_SEND_IF_ASKED, @@ -351,6 +352,7 @@ static gboolean initiate_connection(private_maemo_service_t *this, TRUE, MODE_TUNNEL, ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, 0, 0, NULL, NULL, 0); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP)); ts = traffic_selector_create_dynamic(0, 0, 65535); child_cfg->add_traffic_selector(child_cfg, TRUE, ts); ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0", diff --git a/src/libcharon/plugins/medcli/Makefile.am b/src/libcharon/plugins/medcli/Makefile.am index f645be27e..cfa825980 100644 --- a/src/libcharon/plugins/medcli/Makefile.am +++ b/src/libcharon/plugins/medcli/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-medcli.la diff --git a/src/libcharon/plugins/medcli/Makefile.in b/src/libcharon/plugins/medcli/Makefile.in index b6a04dfe7..919b936c0 100644 --- a/src/libcharon/plugins/medcli/Makefile.in +++ b/src/libcharon/plugins/medcli/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-medcli.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-medcli.la diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index d048b003b..1fb57b928 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -106,6 +106,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, charon->socket->get_port(charon->socket, FALSE), address, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); med_cfg = peer_cfg_create( "mediation", ike_cfg, CERT_NEVER_SEND, UNIQUE_REPLACE, @@ -168,6 +169,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, 0, 0, NULL, NULL, 0); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP)); child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net)); child_cfg->add_traffic_selector(child_cfg, FALSE, ts_from_string(remote_net)); peer_cfg->add_child_cfg(peer_cfg, child_cfg); @@ -242,6 +244,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, 0, 0, NULL, NULL, 0); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP)); child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net)); child_cfg->add_traffic_selector(child_cfg, FALSE, ts_from_string(remote_net)); this->current->add_child_cfg(this->current, child_cfg); @@ -382,6 +385,7 @@ medcli_config_t *medcli_config_create(database_t *db) FRAGMENTATION_NO, 0), ); this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); + this->ike->add_proposal(this->ike, proposal_create_default_aead(PROTO_IKE)); schedule_autoinit(this); diff --git a/src/libcharon/plugins/medsrv/Makefile.am b/src/libcharon/plugins/medsrv/Makefile.am index ec305da21..f21220260 100644 --- a/src/libcharon/plugins/medsrv/Makefile.am +++ b/src/libcharon/plugins/medsrv/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-medsrv.la diff --git a/src/libcharon/plugins/medsrv/Makefile.in b/src/libcharon/plugins/medsrv/Makefile.in index 82d985e57..ce81fb1a8 100644 --- a/src/libcharon/plugins/medsrv/Makefile.in +++ b/src/libcharon/plugins/medsrv/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-medsrv.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-medsrv.la diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c index ac6076ae8..02d805e06 100644 --- a/src/libcharon/plugins/medsrv/medsrv_config.c +++ b/src/libcharon/plugins/medsrv/medsrv_config.c @@ -145,6 +145,7 @@ medsrv_config_t *medsrv_config_create(database_t *db) FRAGMENTATION_NO, 0), ); this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); + this->ike->add_proposal(this->ike, proposal_create_default_aead(PROTO_IKE)); return &this->public; } diff --git a/src/libcharon/plugins/osx_attr/Makefile.am b/src/libcharon/plugins/osx_attr/Makefile.am index f1ff22e60..aa1d46290 100644 --- a/src/libcharon/plugins/osx_attr/Makefile.am +++ b/src/libcharon/plugins/osx_attr/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-osx-attr.la diff --git a/src/libcharon/plugins/osx_attr/Makefile.in b/src/libcharon/plugins/osx_attr/Makefile.in index ce8d67c53..870b42790 100644 --- a/src/libcharon/plugins/osx_attr/Makefile.in +++ b/src/libcharon/plugins/osx_attr/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-osx-attr.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-osx-attr.la diff --git a/src/libcharon/plugins/radattr/Makefile.am b/src/libcharon/plugins/radattr/Makefile.am index a0b0584d6..15d5a0a1f 100644 --- a/src/libcharon/plugins/radattr/Makefile.am +++ b/src/libcharon/plugins/radattr/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libradius AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-radattr.la diff --git a/src/libcharon/plugins/radattr/Makefile.in b/src/libcharon/plugins/radattr/Makefile.in index 3dbebd807..35ebf9975 100644 --- a/src/libcharon/plugins/radattr/Makefile.in +++ b/src/libcharon/plugins/radattr/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -267,6 +267,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -285,6 +286,7 @@ 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@ @@ -312,6 +314,7 @@ 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@ @@ -403,6 +406,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -420,7 +424,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libradius AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-radattr.la @MONOLITHIC_FALSE@libstrongswan_radattr_la_LIBADD = $(top_builddir)/src/libradius/libradius.la diff --git a/src/libcharon/plugins/radattr/radattr_listener.c b/src/libcharon/plugins/radattr/radattr_listener.c index aca83aafc..1d30460ad 100644 --- a/src/libcharon/plugins/radattr/radattr_listener.c +++ b/src/libcharon/plugins/radattr/radattr_listener.c @@ -68,7 +68,7 @@ static void print_radius_attributes(private_radattr_listener_t *this, enumerator = message->create_payload_enumerator(message); while (enumerator->enumerate(enumerator, &payload)) { - if (payload->get_type(payload) == NOTIFY) + if (payload->get_type(payload) == PLV2_NOTIFY) { notify = (notify_payload_t*)payload; if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE) @@ -144,7 +144,7 @@ METHOD(listener_t, message, bool, { if (plain && ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN) && message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) + message->get_payload(message, PLV2_EAP)) { if (incoming) { diff --git a/src/libcharon/plugins/smp/Makefile.am b/src/libcharon/plugins/smp/Makefile.am index 67b4b2a6d..3aa533e56 100644 --- a/src/libcharon/plugins/smp/Makefile.am +++ b/src/libcharon/plugins/smp/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ ${xml_CFLAGS} \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-smp.la diff --git a/src/libcharon/plugins/smp/Makefile.in b/src/libcharon/plugins/smp/Makefile.in index e0134e7a2..35e7f2a87 100644 --- a/src/libcharon/plugins/smp/Makefile.in +++ b/src/libcharon/plugins/smp/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -264,6 +264,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -282,6 +283,7 @@ 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@ @@ -309,6 +311,7 @@ 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@ @@ -400,6 +403,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ ${xml_CFLAGS} \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-smp.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-smp.la diff --git a/src/libcharon/plugins/socket_default/Makefile.am b/src/libcharon/plugins/socket_default/Makefile.am index d734b313f..e524ffd18 100644 --- a/src/libcharon/plugins/socket_default/Makefile.am +++ b/src/libcharon/plugins/socket_default/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-socket-default.la diff --git a/src/libcharon/plugins/socket_default/Makefile.in b/src/libcharon/plugins/socket_default/Makefile.in index 894c1f9dc..bee1259e6 100644 --- a/src/libcharon/plugins/socket_default/Makefile.in +++ b/src/libcharon/plugins/socket_default/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -419,7 +423,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-socket-default.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-socket-default.la diff --git a/src/libcharon/plugins/socket_dynamic/Makefile.am b/src/libcharon/plugins/socket_dynamic/Makefile.am index 04973e5ba..a1e21b98b 100644 --- a/src/libcharon/plugins/socket_dynamic/Makefile.am +++ b/src/libcharon/plugins/socket_dynamic/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-socket-dynamic.la diff --git a/src/libcharon/plugins/socket_dynamic/Makefile.in b/src/libcharon/plugins/socket_dynamic/Makefile.in index a0e2d2d93..073806d64 100644 --- a/src/libcharon/plugins/socket_dynamic/Makefile.in +++ b/src/libcharon/plugins/socket_dynamic/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -419,7 +423,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-socket-dynamic.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-socket-dynamic.la diff --git a/src/libcharon/plugins/socket_win/Makefile.am b/src/libcharon/plugins/socket_win/Makefile.am new file mode 100644 index 000000000..f01178fcc --- /dev/null +++ b/src/libcharon/plugins/socket_win/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = \ + -I${linux_headers} \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-socket-win.la +else +plugin_LTLIBRARIES = libstrongswan-socket-win.la +endif + +libstrongswan_socket_win_la_SOURCES = \ + socket_win_socket.h socket_win_socket.c \ + socket_win_plugin.h socket_win_plugin.c + +libstrongswan_socket_win_la_LDFLAGS = -module -avoid-version +libstrongswan_socket_win_la_LIBADD = -lws2_32 diff --git a/src/libcharon/plugins/socket_win/Makefile.in b/src/libcharon/plugins/socket_win/Makefile.in new file mode 100644 index 000000000..ff38e8158 --- /dev/null +++ b/src/libcharon/plugins/socket_win/Makefile.in @@ -0,0 +1,769 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libcharon/plugins/socket_win +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(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 = +CONFIG_CLEAN_VPATH_FILES = +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; }; \ + } +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_socket_win_la_DEPENDENCIES = +am_libstrongswan_socket_win_la_OBJECTS = socket_win_socket.lo \ + socket_win_plugin.lo +libstrongswan_socket_win_la_OBJECTS = \ + $(am_libstrongswan_socket_win_la_OBJECTS) +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 = +libstrongswan_socket_win_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_socket_win_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_socket_win_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_socket_win_la_rpath = +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 = $(libstrongswan_socket_win_la_SOURCES) +DIST_SOURCES = $(libstrongswan_socket_win_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# 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@ +AM_CPPFLAGS = \ + -I${linux_headers} \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-socket-win.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-socket-win.la +libstrongswan_socket_win_la_SOURCES = \ + socket_win_socket.h socket_win_socket.c \ + socket_win_plugin.h socket_win_plugin.c + +libstrongswan_socket_win_la_LDFLAGS = -module -avoid-version +libstrongswan_socket_win_la_LIBADD = -lws2_32 +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/socket_win/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/socket_win/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): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libstrongswan-socket-win.la: $(libstrongswan_socket_win_la_OBJECTS) $(libstrongswan_socket_win_la_DEPENDENCIES) $(EXTRA_libstrongswan_socket_win_la_DEPENDENCIES) + $(AM_V_CCLD)$(libstrongswan_socket_win_la_LINK) $(am_libstrongswan_socket_win_la_rpath) $(libstrongswan_socket_win_la_OBJECTS) $(libstrongswan_socket_win_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_win_plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_win_socket.Plo@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 + +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: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(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-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + 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-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-pluginLTLIBRARIES install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/socket_win/socket_win_plugin.c b/src/libcharon/plugins/socket_win/socket_win_plugin.c new file mode 100644 index 000000000..a0ef0858a --- /dev/null +++ b/src/libcharon/plugins/socket_win/socket_win_plugin.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "socket_win_plugin.h" +#include "socket_win_socket.h" + +#include <daemon.h> + +typedef struct private_socket_win_plugin_t private_socket_win_plugin_t; + +/** + * Private data of socket plugin + */ +struct private_socket_win_plugin_t { + + /** + * Implements plugin interface + */ + socket_win_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_socket_win_plugin_t *this) +{ + return "socket-win"; +} + +METHOD(plugin_t, destroy, void, + private_socket_win_plugin_t *this) +{ + free(this); +} + +METHOD(plugin_t, get_features, int, + private_socket_win_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(socket_register, socket_win_socket_create), + PLUGIN_PROVIDE(CUSTOM, "socket"), + PLUGIN_DEPENDS(CUSTOM, "kernel-ipsec"), + }; + *features = f; + return countof(f); +} + +/** + * Create instance of socket-win plugin + */ +plugin_t *socket_win_plugin_create() +{ + private_socket_win_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/socket_win/socket_win_plugin.h b/src/libcharon/plugins/socket_win/socket_win_plugin.h new file mode 100644 index 000000000..c4873ce61 --- /dev/null +++ b/src/libcharon/plugins/socket_win/socket_win_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup socket_win socket_win + * @ingroup cplugins + * + * @defgroup socket_win_plugin socket_win_plugin + * @{ @ingroup socket_win + */ + +#ifndef SOCKET_WIN_PLUGIN_H_ +#define SOCKET_WIN_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct socket_win_plugin_t socket_win_plugin_t; + +/** + * Winsock2 based socket implementation plugin. + */ +struct socket_win_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** SOCKET_WIN_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/socket_win/socket_win_socket.c b/src/libcharon/plugins/socket_win/socket_win_socket.c new file mode 100644 index 000000000..5ebe04aac --- /dev/null +++ b/src/libcharon/plugins/socket_win/socket_win_socket.c @@ -0,0 +1,501 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* for WSAID_WSASENDMSG, Windows 7 */ +#define _WIN32_WINNT 0x0601 + +#include "socket_win_socket.h" + +#include <library.h> +#include <hydra.h> +#include <threading/thread.h> +#include <daemon.h> + +#include <mswsock.h> + +/* Maximum size of a packet */ +#define MAX_PACKET 10000 + +/* number of sockets in use */ +#define SOCKET_COUNT 2 + +/* missing on MinGW */ +#ifndef IPV6_V6ONLY +# define IPV6_V6ONLY 27 +#endif + +/* GUIDS to lookup WSASend/RecvMsg */ +static GUID WSARecvMsgGUID = WSAID_WSARECVMSG; +static GUID WSASendMsgGUID = WSAID_WSASENDMSG; + +typedef struct private_socket_win_socket_t private_socket_win_socket_t; + +/** + * Private data of an socket_t object + */ +struct private_socket_win_socket_t { + + /** + * public functions + */ + socket_win_socket_t public; + + /** + * Port for each socket + */ + u_int16_t ports[SOCKET_COUNT]; + + /** + * IPv4/IPv6 dual-use sockets + */ + SOCKET socks[SOCKET_COUNT]; + + /** + * Events to wait for socket data + */ + HANDLE events[SOCKET_COUNT]; + + /** + * Maximum packet size to receive + */ + int max_packet; + + /** + * WSASendMsg function + */ + int WINAPI (*WSASendMsg)(SOCKET, LPWSAMSG, DWORD, LPDWORD, + LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); + + /** + * WSARecvMsg function + */ + int WINAPI (*WSARecvMsg)(SOCKET, LPWSAMSG, LPDWORD, + LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); +}; + +METHOD(socket_t, receiver, status_t, + private_socket_win_socket_t *this, packet_t **out) +{ + char buf[this->max_packet], cbuf[128]; + bool old; + DWORD i, len, err; + WSAMSG msg; + WSABUF data; + WSACMSGHDR *cmsg; + SOCKADDR_IN6 addr; + host_t *src = NULL, *dst = NULL; + packet_t *pkt; + + data.buf = buf; + data.len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.name = (struct sockaddr*)&addr; + msg.namelen = sizeof(addr); + msg.lpBuffers = &data; + msg.dwBufferCount = 1; + msg.Control.buf = cbuf; + msg.Control.len = sizeof(cbuf); + + /* wait for socket events */ + old = thread_cancelability(TRUE); + i = WSAWaitForMultipleEvents(SOCKET_COUNT, this->events, + FALSE, INFINITE, TRUE); + thread_cancelability(old); + if (i < WSA_WAIT_EVENT_0 || i >= WSA_WAIT_EVENT_0 + SOCKET_COUNT) + { + DBG1(DBG_NET, "waiting on sockets failed: %d", WSAGetLastError()); + return FAILED; + } + i -= WSA_WAIT_EVENT_0; + + /* WSAEvents must be reset manually */ + WSAResetEvent(this->events[i]); + + if (this->WSARecvMsg(this->socks[i], &msg, &len, + NULL, NULL) == SOCKET_ERROR) + { + err = WSAGetLastError(); + /* ignore WSAECONNRESET; this is returned for any ICMP port unreachable, + * for a packet we sent, but is most likely not related to the packet + * we try to receive. */ + if (err != WSAECONNRESET) + { + DBG1(DBG_NET, "reading from socket failed: %d", WSAGetLastError()); + } + return FAILED; + } + + DBG3(DBG_NET, "received packet %b", buf, (int)len); + + for (cmsg = WSA_CMSG_FIRSTHDR(&msg); dst == NULL && cmsg != NULL; + cmsg = WSA_CMSG_NXTHDR(&msg, cmsg)) + { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo *pktinfo; + struct sockaddr_in sin = { + .sin_family = AF_INET, + }; + + pktinfo = (struct in_pktinfo*)WSA_CMSG_DATA(cmsg); + sin.sin_addr = pktinfo->ipi_addr; + sin.sin_port = htons(this->ports[i]); + dst = host_create_from_sockaddr((struct sockaddr*)&sin); + } + if (cmsg->cmsg_level == IPPROTO_IPV6 && + cmsg->cmsg_type == IPV6_PKTINFO) + { + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 sin = { + .sin6_family = AF_INET6, + }; + + pktinfo = (struct in6_pktinfo*)WSA_CMSG_DATA(cmsg); + sin.sin6_addr = pktinfo->ipi6_addr; + sin.sin6_port = htons(this->ports[i]); + dst = host_create_from_sockaddr((struct sockaddr*)&sin); + } + } + + if (!dst) + { + DBG1(DBG_NET, "receiving IP destination address failed"); + return FAILED; + } + + switch (dst->get_family(dst)) + { + case AF_INET6: + src = host_create_from_sockaddr((struct sockaddr*)&addr); + break; + case AF_INET: + /* extract v4 address from mapped v6 */ + src = host_create_from_chunk(AF_INET, + chunk_create(addr.sin6_addr.u.Byte + 12, 4), + ntohs(addr.sin6_port)); + break; + } + if (!src) + { + DBG1(DBG_NET, "receiving IP source address failed"); + dst->destroy(dst); + return FAILED; + } + + pkt = packet_create(); + pkt->set_source(pkt, src); + pkt->set_destination(pkt, dst); + DBG2(DBG_NET, "received packet: from %#H to %#H", src, dst); + pkt->set_data(pkt, chunk_clone(chunk_create(buf, len))); + + *out = pkt; + return SUCCESS; +} + +METHOD(socket_t, sender, status_t, + private_socket_win_socket_t *this, packet_t *packet) +{ + u_int16_t port; + int i = -1, j; + host_t *src, *dst; + WSAMSG msg; + DWORD len; + WSABUF data; + WSACMSGHDR *cmsg; + SOCKADDR_IN6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = { + .u = { + .Byte = { + /* v6-mapped-v4 by default */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + }, + }, + }, + }; + char buf[WSA_CMSG_SPACE(max(sizeof(struct in6_pktinfo), + sizeof(struct in_pktinfo)))]; + + src = packet->get_source(packet); + dst = packet->get_destination(packet); + data.len = packet->get_data(packet).len; + data.buf = packet->get_data(packet).ptr; + + DBG2(DBG_NET, "sending packet: from %#H to %#H", src, dst); + + DBG3(DBG_NET, "sending packet %b", data.buf, (int)data.len); + + port = src->get_port(src); + for (j = 0; j < SOCKET_COUNT; j++) + { + if (!port || this->ports[j] == port) + { + i = j; + break; + } + } + if (i == -1) + { + DBG1(DBG_NET, "no socket found to send packet from port %u", port); + return FAILED; + } + + /* copy destination IPv6, or last 32 bits of mapped IPv4 address */ + len = dst->get_address(dst).len; + if (len > sizeof(addr.sin6_addr)) + { + return FAILED; + } + memcpy(addr.sin6_addr.u.Byte + sizeof(addr.sin6_addr) - len, + dst->get_address(dst).ptr, len); + addr.sin6_port = htons(dst->get_port(dst)); + + memset(&msg, 0, sizeof(msg)); + msg.name = (struct sockaddr*)&addr; + msg.namelen = sizeof(addr); + msg.lpBuffers = &data; + msg.dwBufferCount = 1; + + if (!src->is_anyaddr(src)) + { + memset(buf, 0, sizeof(buf)); + msg.Control.buf = buf; + + switch (src->get_family(src)) + { + case AF_INET: + { + struct in_pktinfo *pktinfo; + SOCKADDR_IN *sin; + + msg.Control.len = WSA_CMSG_SPACE(sizeof(*pktinfo)); + cmsg = WSA_CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = WSA_CMSG_LEN(sizeof(*pktinfo)); + pktinfo = (struct in_pktinfo*)WSA_CMSG_DATA(cmsg); + sin = (SOCKADDR_IN*)src->get_sockaddr(src); + pktinfo->ipi_addr = sin->sin_addr; + break; + } + case AF_INET6: + { + struct in6_pktinfo *pktinfo; + SOCKADDR_IN6 *sin; + + msg.Control.len = WSA_CMSG_SPACE(sizeof(*pktinfo)); + cmsg = WSA_CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = WSA_CMSG_LEN(sizeof(*pktinfo)); + pktinfo = (struct in6_pktinfo*)WSA_CMSG_DATA(cmsg); + sin = (SOCKADDR_IN6*)src->get_sockaddr(src); + pktinfo->ipi6_addr = sin->sin6_addr; + break; + } + } + } + + if (this->WSASendMsg(this->socks[i], &msg, 0, &len, + NULL, NULL) == SOCKET_ERROR) + { + DBG1(DBG_NET, "sending packet failed: %d", WSAGetLastError()); + return FAILED; + } + return SUCCESS; +} + +METHOD(socket_t, get_port, u_int16_t, + private_socket_win_socket_t *this, bool nat) +{ + return this->ports[nat != 0]; +} + +METHOD(socket_t, supported_families, socket_family_t, + private_socket_win_socket_t *this) +{ + return SOCKET_FAMILY_IPV4 | SOCKET_FAMILY_IPV6; +} + +/** + * Open an IPv4/IPv6 dual-use socket to send and receive packets + */ +static SOCKET open_socket(private_socket_win_socket_t *this, int i) +{ + SOCKADDR_IN6 addr = { + .sin6_family = AF_INET6, + .sin6_port = htons(this->ports[i]), + }; + int addrlen = sizeof(addr); + BOOL on = TRUE, off = FALSE; + DWORD dwon = TRUE; + SOCKET s; + + s = WSASocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0); + if (s == INVALID_SOCKET) + { + DBG1(DBG_NET, "creating socket failed: %d", WSAGetLastError()); + return INVALID_SOCKET; + } + /* enable IPv4 on IPv6 socket */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (const char*)&off, sizeof(off)) == SOCKET_ERROR) + { + DBG1(DBG_NET, "using dual-mode socket failed: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const char*)&on, sizeof(on)) == SOCKET_ERROR) + { + DBG1(DBG_NET, "enabling SO_REUSEADDR failed: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + if (bind(s, (const struct sockaddr*)&addr, addrlen) == SOCKET_ERROR) + { + DBG1(DBG_NET, "unable to bind socket: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + /* retrieve randomly allocated port if needed */ + if (this->ports[i] == 0) + { + if (getsockname(s, (struct sockaddr*)&addr, + &addrlen) == SOCKET_ERROR) + { + DBG1(DBG_NET, "unable to determine port: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + this->ports[i] = ntohs(addr.sin6_port); + } + /* PKTINFO is required for both protocol families */ + if (setsockopt(s, IPPROTO_IP, IP_PKTINFO, + (char*)&dwon, sizeof(dwon)) == SOCKET_ERROR) + { + DBG1(DBG_NET, "unable to set IP_PKTINFO: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, + (char*)&dwon, sizeof(dwon)) == SOCKET_ERROR) + { + DBG1(DBG_NET, "unable to set IP6_PKTINFO: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + if (!hydra->kernel_interface->bypass_socket(hydra->kernel_interface, + s, AF_INET)) + { + DBG1(DBG_NET, "installing IPv4 IKE bypass policy failed"); + } + if (!hydra->kernel_interface->bypass_socket(hydra->kernel_interface, + s, AF_INET6)) + { + DBG1(DBG_NET, "installing IPv6 IKE bypass policy failed"); + } + return s; +} + +METHOD(socket_t, destroy, void, + private_socket_win_socket_t *this) +{ + int i; + + for (i = 0; i < SOCKET_COUNT; i++) + { + if (this->socks[i] != INVALID_SOCKET) + { + closesocket(this->socks[i]); + } + if (this->events[i] != WSA_INVALID_EVENT) + { + WSACloseEvent(this->events[i]); + } + } + free(this); +} + +/* + * See header for description + */ +socket_win_socket_t *socket_win_socket_create() +{ + private_socket_win_socket_t *this; + DWORD len; + int i; + + INIT(this, + .public = { + .socket = { + .send = _sender, + .receive = _receiver, + .get_port = _get_port, + .supported_families = _supported_families, + .destroy = _destroy, + }, + }, + .ports = { + lib->settings->get_int(lib->settings, + "%s.port", CHARON_UDP_PORT, lib->ns), + lib->settings->get_int(lib->settings, + "%s.port_nat_t", CHARON_NATT_PORT, lib->ns), + }, + .max_packet = lib->settings->get_int(lib->settings, + "%s.max_packet", MAX_PACKET, lib->ns), + ); + + for (i = 0; i < SOCKET_COUNT; i++) + { + this->socks[i] = open_socket(this, i); + this->events[i] = WSACreateEvent(); + } + + for (i = 0; i < SOCKET_COUNT; i++) + { + if (this->events[i] == WSA_INVALID_EVENT || + this->socks[i] == INVALID_SOCKET) + { + DBG1(DBG_NET, "creating socket failed: %d", WSAGetLastError()); + destroy(this); + return NULL; + } + if (WSAEventSelect(this->socks[i], this->events[i], + FD_READ) == SOCKET_ERROR) + { + DBG1(DBG_NET, "WSAEventSelect() failed: %d", WSAGetLastError()); + destroy(this); + return NULL; + } + } + + if (WSAIoctl(this->socks[0], SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSASendMsgGUID, sizeof(WSASendMsgGUID), &this->WSASendMsg, + sizeof(this->WSASendMsg), &len, NULL, NULL) != 0 || + WSAIoctl(this->socks[0], SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSARecvMsgGUID, sizeof(WSARecvMsgGUID), &this->WSARecvMsg, + sizeof(this->WSARecvMsg), &len, NULL, NULL) != 0) + { + DBG1(DBG_NET, "send/recvmsg() lookup failed: %d", WSAGetLastError()); + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libcharon/plugins/socket_win/socket_win_socket.h b/src/libcharon/plugins/socket_win/socket_win_socket.h new file mode 100644 index 000000000..21699c330 --- /dev/null +++ b/src/libcharon/plugins/socket_win/socket_win_socket.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup socket_win_socket socket_win_socket + * @{ @ingroup socket_win + */ + +#ifndef SOCKET_WIN_SOCKET_H_ +#define SOCKET_WIN_SOCKET_H_ + +typedef struct socket_win_socket_t socket_win_socket_t; + +#include <network/socket.h> + +/** + * Winsock2 based socket implementation. + */ +struct socket_win_socket_t { + + /** + * Implements the socket_t interface. + */ + socket_t socket; +}; + +/** + * Create a socket_win_socket instance. + */ +socket_win_socket_t *socket_win_socket_create(); + +#endif /** SOCKET_WIN_SOCKET_H_ @}*/ diff --git a/src/libcharon/plugins/sql/Makefile.am b/src/libcharon/plugins/sql/Makefile.am index fd5693123..c947db892 100644 --- a/src/libcharon/plugins/sql/Makefile.am +++ b/src/libcharon/plugins/sql/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-sql.la diff --git a/src/libcharon/plugins/sql/Makefile.in b/src/libcharon/plugins/sql/Makefile.in index 02967d0dd..208b900e1 100644 --- a/src/libcharon/plugins/sql/Makefile.in +++ b/src/libcharon/plugins/sql/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -264,6 +264,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -282,6 +283,7 @@ 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@ @@ -309,6 +311,7 @@ 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@ @@ -400,6 +403,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -416,7 +420,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-sql.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-sql.la diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index a8d34f2d4..c47c7c0f8 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -153,6 +153,7 @@ static void add_esp_proposals(private_sql_config_t *this, if (use_default) { child->add_proposal(child, proposal_create_default(PROTO_ESP)); + child->add_proposal(child, proposal_create_default_aead(PROTO_ESP)); } } @@ -242,6 +243,7 @@ static void add_ike_proposals(private_sql_config_t *this, if (use_default) { ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); } } diff --git a/src/libcharon/plugins/stroke/Makefile.am b/src/libcharon/plugins/stroke/Makefile.am index 9509b1bd3..b90688791 100644 --- a/src/libcharon/plugins/stroke/Makefile.am +++ b/src/libcharon/plugins/stroke/Makefile.am @@ -7,7 +7,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-stroke.la diff --git a/src/libcharon/plugins/stroke/Makefile.in b/src/libcharon/plugins/stroke/Makefile.in index 253203de7..59a59834a 100644 --- a/src/libcharon/plugins/stroke/Makefile.in +++ b/src/libcharon/plugins/stroke/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -268,6 +268,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -286,6 +287,7 @@ 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@ @@ -313,6 +315,7 @@ 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@ @@ -404,6 +407,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -423,7 +427,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-stroke.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-stroke.la diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index e5e6d9246..62967b006 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -174,10 +174,12 @@ static void add_proposals(private_stroke_config_t *this, char *string, if (ike_cfg) { ike_cfg->add_proposal(ike_cfg, proposal_create_default(proto)); + ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(proto)); } else { child_cfg->add_proposal(child_cfg, proposal_create_default(proto)); + child_cfg->add_proposal(child_cfg, proposal_create_default_aead(proto)); } } @@ -1149,6 +1151,10 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, map_action(msg->add_conn.close_action), msg->add_conn.ipcomp, msg->add_conn.inactivity, msg->add_conn.reqid, &mark_in, &mark_out, msg->add_conn.tfc); + if (msg->add_conn.replay_window != -1) + { + child_cfg->set_replay_window(child_cfg, msg->add_conn.replay_window); + } child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode, msg->add_conn.install_policy); add_ts(this, &msg->add_conn.me, child_cfg, TRUE); diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 169ff2bf6..54dd56e91 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -107,6 +107,19 @@ struct private_stroke_socket_t { }; /** + * Helper macro to log configuration options, but only if they are defined. + */ +#define DBG_OPT(...) VA_ARGS_DISPATCH(DBG_OPT, __VA_ARGS__)(__VA_ARGS__) +#define DBG_OPT2(fmt, val) ({ \ + typeof(val) _val = val; \ + if (_val) { DBG2(DBG_CFG, fmt, _val); } \ +}) +#define DBG_OPT3(fmt, label, val) ({ \ + typeof(val) _val = val; \ + if (_val) { DBG2(DBG_CFG, fmt, label, _val); } \ +}) + +/** * Helper function which corrects the string pointers * in a stroke_msg_t. Strings in a stroke_msg sent over "wire" * contains RELATIVE addresses (relative to the beginning of the @@ -157,22 +170,22 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) pop_string(msg, &end->cert_policy); pop_string(msg, &end->updown); - DBG2(DBG_CFG, " %s=%s", label, end->address); - DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets); - DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip); - DBG2(DBG_CFG, " %sdns=%s", label, end->dns); - DBG2(DBG_CFG, " %sauth=%s", label, end->auth); - DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2); - DBG2(DBG_CFG, " %sid=%s", label, end->id); - DBG2(DBG_CFG, " %sid2=%s", label, end->id2); - DBG2(DBG_CFG, " %srsakey=%s", label, end->rsakey); - DBG2(DBG_CFG, " %scert=%s", label, end->cert); - DBG2(DBG_CFG, " %scert2=%s", label, end->cert2); - DBG2(DBG_CFG, " %sca=%s", label, end->ca); - DBG2(DBG_CFG, " %sca2=%s", label, end->ca2); - DBG2(DBG_CFG, " %sgroups=%s", label, end->groups); - DBG2(DBG_CFG, " %sgroups2=%s", label, end->groups2); - DBG2(DBG_CFG, " %supdown=%s", label, end->updown); + DBG_OPT(" %s=%s", label, end->address); + DBG_OPT(" %ssubnet=%s", label, end->subnets); + DBG_OPT(" %ssourceip=%s", label, end->sourceip); + DBG_OPT(" %sdns=%s", label, end->dns); + DBG_OPT(" %sauth=%s", label, end->auth); + DBG_OPT(" %sauth2=%s", label, end->auth2); + DBG_OPT(" %sid=%s", label, end->id); + DBG_OPT(" %sid2=%s", label, end->id2); + DBG_OPT(" %srsakey=%s", label, end->rsakey); + DBG_OPT(" %scert=%s", label, end->cert); + DBG_OPT(" %scert2=%s", label, end->cert2); + DBG_OPT(" %sca=%s", label, end->ca); + DBG_OPT(" %sca2=%s", label, end->ca2); + DBG_OPT(" %sgroups=%s", label, end->groups); + DBG_OPT(" %sgroups2=%s", label, end->groups2); + DBG_OPT(" %supdown=%s", label, end->updown); } /** @@ -194,20 +207,20 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) pop_string(msg, &msg->add_conn.algorithms.ah); pop_string(msg, &msg->add_conn.ikeme.mediated_by); pop_string(msg, &msg->add_conn.ikeme.peerid); - DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity); - DBG2(DBG_CFG, " aaa_identity=%s", msg->add_conn.aaa_identity); - DBG2(DBG_CFG, " xauth_identity=%s", msg->add_conn.xauth_identity); - DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike); - DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp); - DBG2(DBG_CFG, " ah=%s", msg->add_conn.algorithms.ah); - DBG2(DBG_CFG, " dpddelay=%d", msg->add_conn.dpd.delay); - DBG2(DBG_CFG, " dpdtimeout=%d", msg->add_conn.dpd.timeout); - DBG2(DBG_CFG, " dpdaction=%d", msg->add_conn.dpd.action); - DBG2(DBG_CFG, " closeaction=%d", msg->add_conn.close_action); - DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); - DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by); - DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid); - DBG2(DBG_CFG, " keyexchange=ikev%u", msg->add_conn.version); + DBG_OPT(" eap_identity=%s", msg->add_conn.eap_identity); + DBG_OPT(" aaa_identity=%s", msg->add_conn.aaa_identity); + DBG_OPT(" xauth_identity=%s", msg->add_conn.xauth_identity); + DBG_OPT(" ike=%s", msg->add_conn.algorithms.ike); + DBG_OPT(" esp=%s", msg->add_conn.algorithms.esp); + DBG_OPT(" ah=%s", msg->add_conn.algorithms.ah); + DBG_OPT(" dpddelay=%d", msg->add_conn.dpd.delay); + DBG_OPT(" dpdtimeout=%d", msg->add_conn.dpd.timeout); + DBG_OPT(" dpdaction=%d", msg->add_conn.dpd.action); + DBG_OPT(" closeaction=%d", msg->add_conn.close_action); + DBG_OPT(" mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); + DBG_OPT(" mediated_by=%s", msg->add_conn.ikeme.mediated_by); + DBG_OPT(" me_peerid=%s", msg->add_conn.ikeme.peerid); + DBG_OPT(" keyexchange=ikev%u", msg->add_conn.version); this->config->add(this->config, msg); this->attribute->add_dns(this->attribute, msg); @@ -311,13 +324,13 @@ static void stroke_add_ca(private_stroke_socket_t *this, pop_string(msg, &msg->add_ca.ocspuri); pop_string(msg, &msg->add_ca.ocspuri2); pop_string(msg, &msg->add_ca.certuribase); - DBG2(DBG_CFG, "ca %s", msg->add_ca.name); - DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert); - DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri); - DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2); - DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri); - DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2); - DBG2(DBG_CFG, " certuribase=%s", msg->add_ca.certuribase); + DBG2(DBG_CFG, "ca %s", msg->add_ca.name); + DBG_OPT(" cacert=%s", msg->add_ca.cacert); + DBG_OPT(" crluri=%s", msg->add_ca.crluri); + DBG_OPT(" crluri2=%s", msg->add_ca.crluri2); + DBG_OPT(" ocspuri=%s", msg->add_ca.ocspuri); + DBG_OPT(" ocspuri2=%s", msg->add_ca.ocspuri2); + DBG_OPT(" certuribase=%s", msg->add_ca.certuribase); this->ca->add(this->ca, msg); } @@ -584,8 +597,7 @@ static void stroke_loglevel(private_stroke_socket_t *this, } else { - group = enum_from_name(debug_names, msg->loglevel.type); - if ((int)group < 0) + if (!enum_from_name(debug_names, msg->loglevel.type, &group)) { fprintf(out, "unknown type '%s'!\n", msg->loglevel.type); return; diff --git a/src/libcharon/plugins/systime_fix/Makefile.in b/src/libcharon/plugins/systime_fix/Makefile.in index 76b2c5703..769ad52bc 100644 --- a/src/libcharon/plugins/systime_fix/Makefile.in +++ b/src/libcharon/plugins/systime_fix/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ diff --git a/src/libcharon/plugins/tnc_ifmap/Makefile.am b/src/libcharon/plugins/tnc_ifmap/Makefile.am index dfbb1b632..90fbf4651 100644 --- a/src/libcharon/plugins/tnc_ifmap/Makefile.am +++ b/src/libcharon/plugins/tnc_ifmap/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ ${xml_CFLAGS} \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-tnc-ifmap.la diff --git a/src/libcharon/plugins/tnc_ifmap/Makefile.in b/src/libcharon/plugins/tnc_ifmap/Makefile.in index 194113088..51d46a673 100644 --- a/src/libcharon/plugins/tnc_ifmap/Makefile.in +++ b/src/libcharon/plugins/tnc_ifmap/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -269,6 +269,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -287,6 +288,7 @@ 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@ @@ -314,6 +316,7 @@ 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@ @@ -405,6 +408,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -423,7 +427,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ ${xml_CFLAGS} \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-tnc-ifmap.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-tnc-ifmap.la diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.am b/src/libcharon/plugins/tnc_pdp/Makefile.am index 48de82571..3478c5b30 100644 --- a/src/libcharon/plugins/tnc_pdp/Makefile.am +++ b/src/libcharon/plugins/tnc_pdp/Makefile.am @@ -9,7 +9,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libpttls AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-tnc-pdp.la diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.in b/src/libcharon/plugins/tnc_pdp/Makefile.in index 875aa99d1..531c00c0c 100644 --- a/src/libcharon/plugins/tnc_pdp/Makefile.in +++ b/src/libcharon/plugins/tnc_pdp/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -270,6 +270,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -288,6 +289,7 @@ 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@ @@ -315,6 +317,7 @@ 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@ @@ -406,6 +409,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -427,7 +431,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libpttls AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-tnc-pdp.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-tnc-pdp.la diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c index 89237f564..109c216d5 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c @@ -18,6 +18,7 @@ #include <errno.h> #include <unistd.h> +#include <time.h> #include <radius_message.h> #include <radius_mppe.h> @@ -37,7 +38,7 @@ #include <sa/eap/eap_method.h> typedef struct private_tnc_pdp_t private_tnc_pdp_t; - +typedef struct client_entry_t client_entry_t; /** * Default RADIUS port, when not configured */ @@ -48,6 +49,8 @@ typedef struct private_tnc_pdp_t private_tnc_pdp_t; */ #define MAX_PACKET 4096 +#define RADIUS_RETRANSMIT_TIMEOUT 30 /* seconds */ + /** * private data of tnc_pdp_t */ @@ -99,6 +102,11 @@ struct private_tnc_pdp_t { chunk_t secret; /** + * RADIUS clients + */ + linked_list_t *clients; + + /** * MD5 hasher */ hasher_t *hasher; @@ -121,6 +129,33 @@ struct private_tnc_pdp_t { }; /** + * Client entry helping to detect RADIUS packet retransmissions + */ +struct client_entry_t { + + /** + * IP host address and port of client + */ + host_t *host; + + /** + * Time of last RADIUS Access-Request received from client + */ + time_t last_time; + + /** + * Identifier of last RADIUS Access-Request received from client + */ + uint8_t last_id; +}; + +static void free_client_entry(client_entry_t *this) +{ + this->host->destroy(this->host); + free(this); +} + +/** * Open IPv4 or IPv6 UDP socket */ static int open_udp_socket(int family, u_int16_t port) @@ -663,16 +698,24 @@ static bool radius_receive(private_tnc_pdp_t *this, int fd, watcher_event_t even { radius_message_t *request; char buffer[MAX_PACKET]; + client_entry_t *client; + bool retransmission = FALSE, found = FALSE, stale; + enumerator_t *enumerator; int bytes_read = 0; host_t *source; + uint8_t id; + time_t now; + union { struct sockaddr_in in4; struct sockaddr_in6 in6; } src; + struct iovec iov = { .iov_base = buffer, .iov_len = MAX_PACKET, }; + struct msghdr msg = { .msg_name = &src, .msg_namelen = sizeof(src), @@ -704,7 +747,46 @@ static bool radius_receive(private_tnc_pdp_t *this, int fd, watcher_event_t even if (request->verify(request, NULL, this->secret, this->hasher, this->signer)) { - process_eap(this, request, source); + id = request->get_identifier(request); + now = time(NULL); + + enumerator = this->clients->create_enumerator(this->clients); + while (enumerator->enumerate(enumerator, &client)) + { + stale = client->last_time < now - RADIUS_RETRANSMIT_TIMEOUT; + + if (source->equals(source, client->host)) + { + retransmission = !stale && client->last_id == id; + client->last_id = id; + client->last_time = now; + found = TRUE; + } + else if (stale) + { + this->clients->remove_at(this->clients, enumerator); + free_client_entry(client); + } + } + enumerator->destroy(enumerator); + + if (!found) + { + client = malloc_thing(client_entry_t); + client->host = source->clone(source); + client->last_id = id; + client->last_time = now; + this->clients->insert_last(this->clients, client); + } + if (retransmission) + { + DBG1(DBG_CFG, "ignoring RADIUS Access-Request 0x%02x, " + "already processing", id); + } + else + { + process_eap(this, request, source); + } } request->destroy(request); } @@ -739,6 +821,10 @@ METHOD(tnc_pdp_t, destroy, void, lib->watcher->remove(lib->watcher, this->radius_ipv6); close(this->radius_ipv6); } + if (this->clients) + { + this->clients->destroy_function(this->clients, (void*)free_client_entry); + } DESTROY_IF(this->server); DESTROY_IF(this->signer); DESTROY_IF(this->hasher); @@ -843,6 +929,7 @@ tnc_pdp_t *tnc_pdp_create(void) this->radius_ipv4 = open_udp_socket(AF_INET, radius_port); this->radius_ipv6 = open_udp_socket(AF_INET6, radius_port); this->secret = chunk_from_str(secret); + this->clients = linked_list_create(); this->type = eap_type_from_string(eap_type_str); this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128); diff --git a/src/libcharon/plugins/uci/Makefile.am b/src/libcharon/plugins/uci/Makefile.am index 1fcd9ed25..134ced0e3 100644 --- a/src/libcharon/plugins/uci/Makefile.am +++ b/src/libcharon/plugins/uci/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-uci.la diff --git a/src/libcharon/plugins/uci/Makefile.in b/src/libcharon/plugins/uci/Makefile.in index 8c38ceade..948db7e3c 100644 --- a/src/libcharon/plugins/uci/Makefile.in +++ b/src/libcharon/plugins/uci/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -264,6 +264,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -282,6 +283,7 @@ 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@ @@ -309,6 +311,7 @@ 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@ @@ -400,6 +403,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -416,7 +420,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-uci.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-uci.la diff --git a/src/libcharon/plugins/unit_tester/Makefile.am b/src/libcharon/plugins/unit_tester/Makefile.am index 21cf08c61..b7f8fc319 100644 --- a/src/libcharon/plugins/unit_tester/Makefile.am +++ b/src/libcharon/plugins/unit_tester/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-unit-tester.la diff --git a/src/libcharon/plugins/unit_tester/Makefile.in b/src/libcharon/plugins/unit_tester/Makefile.in index 165590dee..6e4dbff2b 100644 --- a/src/libcharon/plugins/unit_tester/Makefile.in +++ b/src/libcharon/plugins/unit_tester/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -269,6 +269,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -287,6 +288,7 @@ 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@ @@ -314,6 +316,7 @@ 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@ @@ -405,6 +408,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -421,7 +425,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-unit-tester.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-unit-tester.la diff --git a/src/libcharon/plugins/unity/Makefile.am b/src/libcharon/plugins/unity/Makefile.am index b50dc9a03..38923e068 100644 --- a/src/libcharon/plugins/unity/Makefile.am +++ b/src/libcharon/plugins/unity/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-unity.la diff --git a/src/libcharon/plugins/unity/Makefile.in b/src/libcharon/plugins/unity/Makefile.in index efb7e958d..4d411f68e 100644 --- a/src/libcharon/plugins/unity/Makefile.in +++ b/src/libcharon/plugins/unity/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -265,6 +265,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -283,6 +284,7 @@ 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@ @@ -310,6 +312,7 @@ 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@ @@ -401,6 +404,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -417,7 +421,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-unity.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-unity.la diff --git a/src/libcharon/plugins/updown/Makefile.am b/src/libcharon/plugins/updown/Makefile.am index a35909408..f03f4744c 100644 --- a/src/libcharon/plugins/updown/Makefile.am +++ b/src/libcharon/plugins/updown/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-updown.la diff --git a/src/libcharon/plugins/updown/Makefile.in b/src/libcharon/plugins/updown/Makefile.in index 36cf78eca..b377110ec 100644 --- a/src/libcharon/plugins/updown/Makefile.in +++ b/src/libcharon/plugins/updown/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-updown.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-updown.la diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c index 2c3f93298..200f298a1 100644 --- a/src/libcharon/plugins/updown/updown_listener.c +++ b/src/libcharon/plugins/updown/updown_listener.c @@ -344,12 +344,12 @@ METHOD(listener_t, child_updown, bool, "PLUTO_UNIQUEID='%u' " "PLUTO_ME='%H' " "PLUTO_MY_ID='%Y' " - "PLUTO_MY_CLIENT='%H/%u' " + "PLUTO_MY_CLIENT='%+H/%u' " "PLUTO_MY_PORT='%u' " "PLUTO_MY_PROTOCOL='%u' " "PLUTO_PEER='%H' " "PLUTO_PEER_ID='%Y' " - "PLUTO_PEER_CLIENT='%H/%u' " + "PLUTO_PEER_CLIENT='%+H/%u' " "PLUTO_PEER_PORT='%u' " "PLUTO_PEER_PROTOCOL='%u' " "%s" diff --git a/src/libcharon/plugins/vici/Makefile.am b/src/libcharon/plugins/vici/Makefile.am new file mode 100644 index 000000000..7e459c58d --- /dev/null +++ b/src/libcharon/plugins/vici/Makefile.am @@ -0,0 +1,69 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon \ + -DIPSEC_PIDDIR=\"${piddir}\" + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-vici.la +else +plugin_LTLIBRARIES = libstrongswan-vici.la +endif + +libstrongswan_vici_la_SOURCES = \ + vici_socket.h vici_socket.c \ + vici_message.h vici_message.c \ + vici_builder.h vici_builder.c \ + vici_dispatcher.h vici_dispatcher.c \ + vici_query.h vici_query.c \ + vici_control.h vici_control.c \ + vici_config.h vici_config.c \ + vici_cred.h vici_cred.c \ + vici_attribute.h vici_attribute.c \ + vici_logger.h vici_logger.c \ + vici_plugin.h vici_plugin.c + +libstrongswan_vici_la_LDFLAGS = -module -avoid-version + + +EXTRA_DIST = README.md + + +ipseclib_LTLIBRARIES = libvici.la + +libvici_la_SOURCES = \ + vici_message.c vici_message.h \ + vici_builder.c vici_builder.h \ + libvici.c libvici.h + +libvici_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la + + +TESTS = vici_tests + +check_PROGRAMS = $(TESTS) + +vici_tests_SOURCES = \ + suites/test_socket.c \ + suites/test_message.c \ + suites/test_request.c \ + suites/test_event.c \ + vici_socket.c \ + vici_message.c \ + vici_builder.c \ + vici_dispatcher.c \ + libvici.c \ + vici_tests.h vici_tests.c + +vici_tests_CFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libstrongswan/tests \ + @COVERAGE_CFLAGS@ + +vici_tests_LDFLAGS = @COVERAGE_LDFLAGS@ +vici_tests_LDADD = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libstrongswan/tests/libtest.la diff --git a/src/libcharon/plugins/vici/Makefile.in b/src/libcharon/plugins/vici/Makefile.in new file mode 100644 index 000000000..e0a6a1b5d --- /dev/null +++ b/src/libcharon/plugins/vici/Makefile.in @@ -0,0 +1,1183 @@ +# 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@ +TESTS = vici_tests$(EXEEXT) +check_PROGRAMS = $(am__EXEEXT_1) +subdir = src/libcharon/plugins/vici +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(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 = +CONFIG_CLEAN_VPATH_FILES = +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; }; \ + } +am__installdirs = "$(DESTDIR)$(ipseclibdir)" "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(ipseclib_LTLIBRARIES) $(noinst_LTLIBRARIES) \ + $(plugin_LTLIBRARIES) +libstrongswan_vici_la_LIBADD = +am_libstrongswan_vici_la_OBJECTS = vici_socket.lo vici_message.lo \ + vici_builder.lo vici_dispatcher.lo vici_query.lo \ + vici_control.lo vici_config.lo vici_cred.lo vici_attribute.lo \ + vici_logger.lo vici_plugin.lo +libstrongswan_vici_la_OBJECTS = $(am_libstrongswan_vici_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libstrongswan_vici_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_vici_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_vici_la_rpath = -rpath $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_vici_la_rpath = +libvici_la_DEPENDENCIES = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +am_libvici_la_OBJECTS = vici_message.lo vici_builder.lo libvici.lo +libvici_la_OBJECTS = $(am_libvici_la_OBJECTS) +am__EXEEXT_1 = vici_tests$(EXEEXT) +am__dirstamp = $(am__leading_dot)dirstamp +am_vici_tests_OBJECTS = suites/vici_tests-test_socket.$(OBJEXT) \ + suites/vici_tests-test_message.$(OBJEXT) \ + suites/vici_tests-test_request.$(OBJEXT) \ + suites/vici_tests-test_event.$(OBJEXT) \ + vici_tests-vici_socket.$(OBJEXT) \ + vici_tests-vici_message.$(OBJEXT) \ + vici_tests-vici_builder.$(OBJEXT) \ + vici_tests-vici_dispatcher.$(OBJEXT) \ + vici_tests-libvici.$(OBJEXT) vici_tests-vici_tests.$(OBJEXT) +vici_tests_OBJECTS = $(am_vici_tests_OBJECTS) +vici_tests_DEPENDENCIES = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libstrongswan/tests/libtest.la +vici_tests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(vici_tests_CFLAGS) \ + $(CFLAGS) $(vici_tests_LDFLAGS) $(LDFLAGS) -o $@ +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 = $(libstrongswan_vici_la_SOURCES) $(libvici_la_SOURCES) \ + $(vici_tests_SOURCES) +DIST_SOURCES = $(libstrongswan_vici_la_SOURCES) $(libvici_la_SOURCES) \ + $(vici_tests_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# 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 +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COVERAGE_CFLAGS = @COVERAGE_CFLAGS@ +COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +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@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon \ + -DIPSEC_PIDDIR=\"${piddir}\" + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-vici.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-vici.la +libstrongswan_vici_la_SOURCES = \ + vici_socket.h vici_socket.c \ + vici_message.h vici_message.c \ + vici_builder.h vici_builder.c \ + vici_dispatcher.h vici_dispatcher.c \ + vici_query.h vici_query.c \ + vici_control.h vici_control.c \ + vici_config.h vici_config.c \ + vici_cred.h vici_cred.c \ + vici_attribute.h vici_attribute.c \ + vici_logger.h vici_logger.c \ + vici_plugin.h vici_plugin.c + +libstrongswan_vici_la_LDFLAGS = -module -avoid-version +EXTRA_DIST = README.md +ipseclib_LTLIBRARIES = libvici.la +libvici_la_SOURCES = \ + vici_message.c vici_message.h \ + vici_builder.c vici_builder.h \ + libvici.c libvici.h + +libvici_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la +vici_tests_SOURCES = \ + suites/test_socket.c \ + suites/test_message.c \ + suites/test_request.c \ + suites/test_event.c \ + vici_socket.c \ + vici_message.c \ + vici_builder.c \ + vici_dispatcher.c \ + libvici.c \ + vici_tests.h vici_tests.c + +vici_tests_CFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libstrongswan/tests \ + @COVERAGE_CFLAGS@ + +vici_tests_LDFLAGS = @COVERAGE_LDFLAGS@ +vici_tests_LDADD = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libstrongswan/tests/libtest.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/vici/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/vici/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): + +install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(ipseclibdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(ipseclibdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(ipseclibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \ + } + +uninstall-ipseclibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(ipseclibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \ + done + +clean-ipseclibLTLIBRARIES: + -test -z "$(ipseclib_LTLIBRARIES)" || rm -f $(ipseclib_LTLIBRARIES) + @list='$(ipseclib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libstrongswan-vici.la: $(libstrongswan_vici_la_OBJECTS) $(libstrongswan_vici_la_DEPENDENCIES) $(EXTRA_libstrongswan_vici_la_DEPENDENCIES) + $(AM_V_CCLD)$(libstrongswan_vici_la_LINK) $(am_libstrongswan_vici_la_rpath) $(libstrongswan_vici_la_OBJECTS) $(libstrongswan_vici_la_LIBADD) $(LIBS) + +libvici.la: $(libvici_la_OBJECTS) $(libvici_la_DEPENDENCIES) $(EXTRA_libvici_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) -rpath $(ipseclibdir) $(libvici_la_OBJECTS) $(libvici_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_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 +suites/$(am__dirstamp): + @$(MKDIR_P) suites + @: > suites/$(am__dirstamp) +suites/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) suites/$(DEPDIR) + @: > suites/$(DEPDIR)/$(am__dirstamp) +suites/vici_tests-test_socket.$(OBJEXT): suites/$(am__dirstamp) \ + suites/$(DEPDIR)/$(am__dirstamp) +suites/vici_tests-test_message.$(OBJEXT): suites/$(am__dirstamp) \ + suites/$(DEPDIR)/$(am__dirstamp) +suites/vici_tests-test_request.$(OBJEXT): suites/$(am__dirstamp) \ + suites/$(DEPDIR)/$(am__dirstamp) +suites/vici_tests-test_event.$(OBJEXT): suites/$(am__dirstamp) \ + suites/$(DEPDIR)/$(am__dirstamp) + +vici_tests$(EXEEXT): $(vici_tests_OBJECTS) $(vici_tests_DEPENDENCIES) $(EXTRA_vici_tests_DEPENDENCIES) + @rm -f vici_tests$(EXEEXT) + $(AM_V_CCLD)$(vici_tests_LINK) $(vici_tests_OBJECTS) $(vici_tests_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f suites/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvici.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_attribute.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_builder.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_config.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_control.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_cred.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_dispatcher.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_logger.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_message.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_query.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_socket.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_tests-libvici.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_tests-vici_builder.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_tests-vici_dispatcher.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_tests-vici_message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_tests-vici_socket.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici_tests-vici_tests.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/vici_tests-test_event.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/vici_tests-test_message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/vici_tests-test_request.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/vici_tests-test_socket.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 $@ $< + +suites/vici_tests-test_socket.o: suites/test_socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT suites/vici_tests-test_socket.o -MD -MP -MF suites/$(DEPDIR)/vici_tests-test_socket.Tpo -c -o suites/vici_tests-test_socket.o `test -f 'suites/test_socket.c' || echo '$(srcdir)/'`suites/test_socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/vici_tests-test_socket.Tpo suites/$(DEPDIR)/vici_tests-test_socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_socket.c' object='suites/vici_tests-test_socket.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o suites/vici_tests-test_socket.o `test -f 'suites/test_socket.c' || echo '$(srcdir)/'`suites/test_socket.c + +suites/vici_tests-test_socket.obj: suites/test_socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT suites/vici_tests-test_socket.obj -MD -MP -MF suites/$(DEPDIR)/vici_tests-test_socket.Tpo -c -o suites/vici_tests-test_socket.obj `if test -f 'suites/test_socket.c'; then $(CYGPATH_W) 'suites/test_socket.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_socket.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/vici_tests-test_socket.Tpo suites/$(DEPDIR)/vici_tests-test_socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_socket.c' object='suites/vici_tests-test_socket.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o suites/vici_tests-test_socket.obj `if test -f 'suites/test_socket.c'; then $(CYGPATH_W) 'suites/test_socket.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_socket.c'; fi` + +suites/vici_tests-test_message.o: suites/test_message.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT suites/vici_tests-test_message.o -MD -MP -MF suites/$(DEPDIR)/vici_tests-test_message.Tpo -c -o suites/vici_tests-test_message.o `test -f 'suites/test_message.c' || echo '$(srcdir)/'`suites/test_message.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/vici_tests-test_message.Tpo suites/$(DEPDIR)/vici_tests-test_message.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_message.c' object='suites/vici_tests-test_message.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o suites/vici_tests-test_message.o `test -f 'suites/test_message.c' || echo '$(srcdir)/'`suites/test_message.c + +suites/vici_tests-test_message.obj: suites/test_message.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT suites/vici_tests-test_message.obj -MD -MP -MF suites/$(DEPDIR)/vici_tests-test_message.Tpo -c -o suites/vici_tests-test_message.obj `if test -f 'suites/test_message.c'; then $(CYGPATH_W) 'suites/test_message.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_message.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/vici_tests-test_message.Tpo suites/$(DEPDIR)/vici_tests-test_message.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_message.c' object='suites/vici_tests-test_message.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o suites/vici_tests-test_message.obj `if test -f 'suites/test_message.c'; then $(CYGPATH_W) 'suites/test_message.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_message.c'; fi` + +suites/vici_tests-test_request.o: suites/test_request.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT suites/vici_tests-test_request.o -MD -MP -MF suites/$(DEPDIR)/vici_tests-test_request.Tpo -c -o suites/vici_tests-test_request.o `test -f 'suites/test_request.c' || echo '$(srcdir)/'`suites/test_request.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/vici_tests-test_request.Tpo suites/$(DEPDIR)/vici_tests-test_request.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_request.c' object='suites/vici_tests-test_request.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o suites/vici_tests-test_request.o `test -f 'suites/test_request.c' || echo '$(srcdir)/'`suites/test_request.c + +suites/vici_tests-test_request.obj: suites/test_request.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT suites/vici_tests-test_request.obj -MD -MP -MF suites/$(DEPDIR)/vici_tests-test_request.Tpo -c -o suites/vici_tests-test_request.obj `if test -f 'suites/test_request.c'; then $(CYGPATH_W) 'suites/test_request.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_request.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/vici_tests-test_request.Tpo suites/$(DEPDIR)/vici_tests-test_request.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_request.c' object='suites/vici_tests-test_request.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o suites/vici_tests-test_request.obj `if test -f 'suites/test_request.c'; then $(CYGPATH_W) 'suites/test_request.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_request.c'; fi` + +suites/vici_tests-test_event.o: suites/test_event.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT suites/vici_tests-test_event.o -MD -MP -MF suites/$(DEPDIR)/vici_tests-test_event.Tpo -c -o suites/vici_tests-test_event.o `test -f 'suites/test_event.c' || echo '$(srcdir)/'`suites/test_event.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/vici_tests-test_event.Tpo suites/$(DEPDIR)/vici_tests-test_event.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_event.c' object='suites/vici_tests-test_event.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o suites/vici_tests-test_event.o `test -f 'suites/test_event.c' || echo '$(srcdir)/'`suites/test_event.c + +suites/vici_tests-test_event.obj: suites/test_event.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT suites/vici_tests-test_event.obj -MD -MP -MF suites/$(DEPDIR)/vici_tests-test_event.Tpo -c -o suites/vici_tests-test_event.obj `if test -f 'suites/test_event.c'; then $(CYGPATH_W) 'suites/test_event.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_event.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/vici_tests-test_event.Tpo suites/$(DEPDIR)/vici_tests-test_event.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_event.c' object='suites/vici_tests-test_event.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o suites/vici_tests-test_event.obj `if test -f 'suites/test_event.c'; then $(CYGPATH_W) 'suites/test_event.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_event.c'; fi` + +vici_tests-vici_socket.o: vici_socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_socket.o -MD -MP -MF $(DEPDIR)/vici_tests-vici_socket.Tpo -c -o vici_tests-vici_socket.o `test -f 'vici_socket.c' || echo '$(srcdir)/'`vici_socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_socket.Tpo $(DEPDIR)/vici_tests-vici_socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_socket.c' object='vici_tests-vici_socket.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_socket.o `test -f 'vici_socket.c' || echo '$(srcdir)/'`vici_socket.c + +vici_tests-vici_socket.obj: vici_socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_socket.obj -MD -MP -MF $(DEPDIR)/vici_tests-vici_socket.Tpo -c -o vici_tests-vici_socket.obj `if test -f 'vici_socket.c'; then $(CYGPATH_W) 'vici_socket.c'; else $(CYGPATH_W) '$(srcdir)/vici_socket.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_socket.Tpo $(DEPDIR)/vici_tests-vici_socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_socket.c' object='vici_tests-vici_socket.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_socket.obj `if test -f 'vici_socket.c'; then $(CYGPATH_W) 'vici_socket.c'; else $(CYGPATH_W) '$(srcdir)/vici_socket.c'; fi` + +vici_tests-vici_message.o: vici_message.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_message.o -MD -MP -MF $(DEPDIR)/vici_tests-vici_message.Tpo -c -o vici_tests-vici_message.o `test -f 'vici_message.c' || echo '$(srcdir)/'`vici_message.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_message.Tpo $(DEPDIR)/vici_tests-vici_message.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_message.c' object='vici_tests-vici_message.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_message.o `test -f 'vici_message.c' || echo '$(srcdir)/'`vici_message.c + +vici_tests-vici_message.obj: vici_message.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_message.obj -MD -MP -MF $(DEPDIR)/vici_tests-vici_message.Tpo -c -o vici_tests-vici_message.obj `if test -f 'vici_message.c'; then $(CYGPATH_W) 'vici_message.c'; else $(CYGPATH_W) '$(srcdir)/vici_message.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_message.Tpo $(DEPDIR)/vici_tests-vici_message.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_message.c' object='vici_tests-vici_message.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_message.obj `if test -f 'vici_message.c'; then $(CYGPATH_W) 'vici_message.c'; else $(CYGPATH_W) '$(srcdir)/vici_message.c'; fi` + +vici_tests-vici_builder.o: vici_builder.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_builder.o -MD -MP -MF $(DEPDIR)/vici_tests-vici_builder.Tpo -c -o vici_tests-vici_builder.o `test -f 'vici_builder.c' || echo '$(srcdir)/'`vici_builder.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_builder.Tpo $(DEPDIR)/vici_tests-vici_builder.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_builder.c' object='vici_tests-vici_builder.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_builder.o `test -f 'vici_builder.c' || echo '$(srcdir)/'`vici_builder.c + +vici_tests-vici_builder.obj: vici_builder.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_builder.obj -MD -MP -MF $(DEPDIR)/vici_tests-vici_builder.Tpo -c -o vici_tests-vici_builder.obj `if test -f 'vici_builder.c'; then $(CYGPATH_W) 'vici_builder.c'; else $(CYGPATH_W) '$(srcdir)/vici_builder.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_builder.Tpo $(DEPDIR)/vici_tests-vici_builder.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_builder.c' object='vici_tests-vici_builder.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_builder.obj `if test -f 'vici_builder.c'; then $(CYGPATH_W) 'vici_builder.c'; else $(CYGPATH_W) '$(srcdir)/vici_builder.c'; fi` + +vici_tests-vici_dispatcher.o: vici_dispatcher.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_dispatcher.o -MD -MP -MF $(DEPDIR)/vici_tests-vici_dispatcher.Tpo -c -o vici_tests-vici_dispatcher.o `test -f 'vici_dispatcher.c' || echo '$(srcdir)/'`vici_dispatcher.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_dispatcher.Tpo $(DEPDIR)/vici_tests-vici_dispatcher.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_dispatcher.c' object='vici_tests-vici_dispatcher.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_dispatcher.o `test -f 'vici_dispatcher.c' || echo '$(srcdir)/'`vici_dispatcher.c + +vici_tests-vici_dispatcher.obj: vici_dispatcher.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_dispatcher.obj -MD -MP -MF $(DEPDIR)/vici_tests-vici_dispatcher.Tpo -c -o vici_tests-vici_dispatcher.obj `if test -f 'vici_dispatcher.c'; then $(CYGPATH_W) 'vici_dispatcher.c'; else $(CYGPATH_W) '$(srcdir)/vici_dispatcher.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_dispatcher.Tpo $(DEPDIR)/vici_tests-vici_dispatcher.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_dispatcher.c' object='vici_tests-vici_dispatcher.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_dispatcher.obj `if test -f 'vici_dispatcher.c'; then $(CYGPATH_W) 'vici_dispatcher.c'; else $(CYGPATH_W) '$(srcdir)/vici_dispatcher.c'; fi` + +vici_tests-libvici.o: libvici.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-libvici.o -MD -MP -MF $(DEPDIR)/vici_tests-libvici.Tpo -c -o vici_tests-libvici.o `test -f 'libvici.c' || echo '$(srcdir)/'`libvici.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-libvici.Tpo $(DEPDIR)/vici_tests-libvici.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libvici.c' object='vici_tests-libvici.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-libvici.o `test -f 'libvici.c' || echo '$(srcdir)/'`libvici.c + +vici_tests-libvici.obj: libvici.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-libvici.obj -MD -MP -MF $(DEPDIR)/vici_tests-libvici.Tpo -c -o vici_tests-libvici.obj `if test -f 'libvici.c'; then $(CYGPATH_W) 'libvici.c'; else $(CYGPATH_W) '$(srcdir)/libvici.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-libvici.Tpo $(DEPDIR)/vici_tests-libvici.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libvici.c' object='vici_tests-libvici.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-libvici.obj `if test -f 'libvici.c'; then $(CYGPATH_W) 'libvici.c'; else $(CYGPATH_W) '$(srcdir)/libvici.c'; fi` + +vici_tests-vici_tests.o: vici_tests.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_tests.o -MD -MP -MF $(DEPDIR)/vici_tests-vici_tests.Tpo -c -o vici_tests-vici_tests.o `test -f 'vici_tests.c' || echo '$(srcdir)/'`vici_tests.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_tests.Tpo $(DEPDIR)/vici_tests-vici_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_tests.c' object='vici_tests-vici_tests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_tests.o `test -f 'vici_tests.c' || echo '$(srcdir)/'`vici_tests.c + +vici_tests-vici_tests.obj: vici_tests.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -MT vici_tests-vici_tests.obj -MD -MP -MF $(DEPDIR)/vici_tests-vici_tests.Tpo -c -o vici_tests-vici_tests.obj `if test -f 'vici_tests.c'; then $(CYGPATH_W) 'vici_tests.c'; else $(CYGPATH_W) '$(srcdir)/vici_tests.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/vici_tests-vici_tests.Tpo $(DEPDIR)/vici_tests-vici_tests.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vici_tests.c' object='vici_tests-vici_tests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vici_tests_CFLAGS) $(CFLAGS) -c -o vici_tests-vici_tests.obj `if test -f 'vici_tests.c'; then $(CYGPATH_W) 'vici_tests.c'; else $(CYGPATH_W) '$(srcdir)/vici_tests.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +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 + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(ipseclibdir)" "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f suites/$(DEPDIR)/$(am__dirstamp) + -rm -f suites/$(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." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-ipseclibLTLIBRARIES \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) suites/$(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-ipseclibLTLIBRARIES install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) suites/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-ipseclibLTLIBRARIES \ + uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-ipseclibLTLIBRARIES \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + 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-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-ipseclibLTLIBRARIES \ + install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-ipseclibLTLIBRARIES uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md new file mode 100644 index 000000000..aeabbbd4d --- /dev/null +++ b/src/libcharon/plugins/vici/README.md @@ -0,0 +1,176 @@ +# The Versatile IKE Control Interface (VICI) protocol # + +The vici plugin implements the server side of an IPC protocol to configure, +monitor and control the IKE daemon charon. It uses request/response and event +messages to communicate over a reliable stream based transport. + +## Transport protocol ## + +To provide the service, the plugin opens a listening socket using a reliable, +stream based transport. charon relies on the different stream service +abstractions provided by libstrongswan, such as TCP and UNIX sockets. + +A client connects to this service to access functionality. It may send an +arbitrary number of packets over the connection before closing it. + +To exchange data, the transport protocol is segmented into byte sequences. +Each byte sequence is prefixed by a 32-bit length header in network order, +followed by the data. The maximum segment length is currently limited to 512KB +of data, and the length field contains the length of the data only, not +including the length field itself. + +The order of byte sequences must be strict, byte sequences must arrive in the +same order as sent. + +## Packet layer ## + +Within the byte sequences defined by the transport layer, both the client +and the server can exchange packets. The type of packet defines its structure +and purpose. The packet type is a 8-bit identifier, and is the first byte +in a transport layer byte sequence. The length of the packet is given by the +transport layer. + +While a packet type may define the format of the wrapped data freely, currently +all types either contain a name, a message or both. The following packet types +are currently defined: + +* _CMD_REQUEST = 0_: A named request message +* _CMD_RESPONSE = 1_: An unnamed response message for a request +* _CMD_UNKNOWN = 2_: An unnamed response if requested command is unknown +* _EVENT_REGISTER = 3_: A named event registration request +* _EVENT_UNREGISTER = 4_: A named event deregistration request +* _EVENT_CONFIRM = 5_: An unnamed response for successful event (de-)registration +* _EVENT_UNKNOWN = 6_: A unnamed response if event (de-)registration failed +* _EVENT = 7_: A named event message + +For packets having a named type, after the packet type an 8-bit length header +of the name follows, indicating the string length in bytes of the name tag, not +including the length field itself. The name is an ASCII string that is not +null-terminated. + +The rest of the packet forms the exchanged message, the length is determined +by the transport byte sequence length, subtracting the packet type and +the optional name tag in some messages. + +### Commands ### + +Commands are currently always requested by the client. The server replies with +a response, or with a CMD_UNKNOWN failure message to let the client know +that it does not have a handler for such a command. There is no sequence number +to associate responses to requests, so only one command can be active at +a time on a single connection. + +### Events ### + +To receive event messages, the client explicitly registers for events by name, +and also unregisters if it does not want to receive events of the named kind +anymore. The server confirms event registration using EVENT_CONFIRM, or +indicates that there is no such event source with EVENT_UNKNOWN. + +Events may get raised at any time while registered, even during an active +request command. This mechanism is used to feed continuous data during a request, +for example. + +## Message format ## + +The defined packet types optionally wrap a message with additional data. +Messages are currently used in CMD_REQUEST/CMD_RESPONSE, and in EVENT packets. +A message uses a hierarchial tree of sections. Each section (or the implicit +root section) contains an arbitrary set of key/value pairs, lists and +sub-sections. The length of a message is not part of the message itself, but +the wrapping layer, usually calculated from the transport byte sequence length. + +The message encoding consists of a sequence of elements. Each element starts +with the element type, optionally followed by an element name and/or an element +value. Currently the following message element types are defined: + +* _SECTION_START = 0_: Begin a new section having a name +* _SECTION_END = 1_: End a previously started section +* _KEY_VALUE = 2_: Define a value for a named key in the current section +* _LIST_START = 3_: Begin a named list for list items +* _LIST_ITEM = 4_: Define an unnamed item value in the current list +* _LIST_END = 5_: End a previously started list + +Types are encoded as 8-bit values. Types having a name (SECTION_START, +KEY_VALUE and LIST_START) have an ASCII string following the type, which itself +uses an 8-bit length header. The string must not be null-terminated, the string +length does not include the length field itself. + +Types having a value (KEY_VALUE and LIST_ITEM) have a raw blob sequence, +prefixed with a 16-bit network order length. The blob follows the type or the +name tag if available, the length defined by the length field does not include +the length field itself. + +The interpretation of any value is not defined by the message format; it can +take arbitrary blobs. The application may specify types for specific keys, such +as strings or integer representations. + +### Sections ### + +Sections may be opened in the implicit root section, or any previously section. +They can be nested to arbitrary levels. A SECTION_END marker always closes +the last opened section; SECTION_START and SECTION_END items must be balanced +in a valid message. + +### Key/Values ### + +Key/Value pair elements may appear in the implicit root section or any explicit +sub-section at any level. Key names must be unique in the current section, use +lists to define multiple values for a key. Key/values may not appear in lists, +use a sub-section instead. + +### Lists ### + +Lists may appear at the same locations as Key/Values, and may not be nested. +Only a single list may be opened at the same time, and all lists must be closed +in valid messages. After opening a list, only list items may appear before the +list closing element. Empty lists are allowed, list items may appear within +lists only. + +### Encoding example ### + +Consider the following structure using pseudo-markup for this example: + + key1 = value1 + section1 = { + sub-section = { + key2 = value2 + } + list1 = [ item1, item2 ] + } + +The example above reprensents a valid tree structure, that gets encoded as +the following C array: + + char msg[] = { + /* key1 = value1 */ + 2, 4,'k','e','y','1', 0,6,'v','a','l','u','e','1', + /* section1 */ + 0, 8,'s','e','c','t','i','o','n','1', + /* sub-section */ + 0, 11,'s','u','b','-','s','e','c','t','i','o','n', + /* key2 = value2 */ + 2, 4,'k','e','y','2', 0,6,'v','a','l','u','e','2', + /* sub-section end */ + 1, + /* list1 */ + 3, 5, 'l','i','s','t','1', + /* item1 */ + 4, 0,5,'i','t','e','m','1', + /* item2 */ + 4, 0,5,'i','t','e','m','2', + /* list1 end */ + 5, + /* section1 end */ + 1, + }; + +# libvici C client library # + +libvici is the reference implementation of a C client library implementing +the vici protocol. It builds upon libstrongswan, but provides a stable API +to implement client applications in the C programming language. libvici uses +the libstrongswan thread pool to deliver event messages asynchronously. + +More information about the libvici API is available in the libvici.h header +file. diff --git a/src/libcharon/plugins/vici/libvici.c b/src/libcharon/plugins/vici/libvici.c new file mode 100644 index 000000000..a2cbb3082 --- /dev/null +++ b/src/libcharon/plugins/vici/libvici.c @@ -0,0 +1,764 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "libvici.h" +#include "vici_builder.h" +#include "vici_dispatcher.h" +#include "vici_socket.h" + +#include <library.h> +#include <threading/mutex.h> +#include <threading/condvar.h> +#include <collections/hashtable.h> + +#include <errno.h> + +/** + * Event registration + */ +typedef struct { + /** name of event */ + char *name; + /** callback function */ + vici_event_cb_t cb; + /** user data for callback */ + void *user; +} event_t; + +/** + * Wait state signaled by asynchronous on_read callback + */ +typedef enum { + WAIT_IDLE = 0, + WAIT_SUCCESS, + WAIT_FAILURE, + WAIT_READ_ERROR, +} wait_state_t; + +/** + * Private vici connection contex. + */ +struct vici_conn_t { + /** connection stream */ + stream_t *stream; + /** event registrations, as char* => event_t */ + hashtable_t *events; + /** connection lock */ + mutex_t *mutex; + /** condvar to signal incoming response */ + condvar_t *cond; + /** queued response message */ + chunk_t queue; + /** asynchronous read error */ + int error; + /** wait state */ + wait_state_t wait; +}; + +/** + * Private vici request message. + */ +struct vici_req_t { + /** connection context */ + vici_conn_t *conn; + /** name of request message */ + char *name; + /** message builder */ + vici_builder_t *b; +}; + +/** + * Private vici response/event message. + */ +struct vici_res_t { + /** response message */ + vici_message_t *message; + /** allocated strings */ + linked_list_t *strings; + /** item enumerator */ + enumerator_t *enumerator; + /** currently enumerating type */ + vici_type_t type; + /** currently enumerating name */ + char *name; + /** currently enumerating value */ + chunk_t value; + /** section nesting level of callback parser */ + int level; +}; + +/** + * Signal wait result for waiting user thread + */ +static bool wait_result(vici_conn_t *conn, wait_state_t wait) +{ + conn->mutex->lock(conn->mutex); + conn->wait = wait; + conn->mutex->unlock(conn->mutex); + conn->cond->signal(conn->cond); + return FALSE; +} + +/** + * Signal wait error result for waiting user thread + */ +static bool read_error(vici_conn_t *conn, int err) +{ + conn->error = err; + return wait_result(conn, WAIT_READ_ERROR); +} + +/** + * Handle a command response message + */ +static bool handle_response(vici_conn_t *conn, u_int32_t len) +{ + chunk_t buf; + + buf = chunk_alloc(len); + if (!conn->stream->read_all(conn->stream, buf.ptr, buf.len)) + { + free(buf.ptr); + return read_error(conn, errno); + } + conn->queue = buf; + return wait_result(conn, WAIT_SUCCESS); +} + +/** + * Dispatch received event message + */ +static bool handle_event(vici_conn_t *conn, u_int32_t len) +{ + vici_message_t *message; + event_t *event; + u_int8_t namelen; + char name[257], *buf; + + if (len < sizeof(namelen)) + { + return read_error(conn, EBADMSG); + } + if (!conn->stream->read_all(conn->stream, &namelen, sizeof(namelen))) + { + return read_error(conn, errno); + } + if (namelen > len - sizeof(namelen)) + { + return read_error(conn, EBADMSG); + } + if (!conn->stream->read_all(conn->stream, name, namelen)) + { + return read_error(conn, errno); + } + name[namelen] = '\0'; + len -= sizeof(namelen) + namelen; + buf = malloc(len); + if (!conn->stream->read_all(conn->stream, buf, len)) + { + free(buf); + return read_error(conn, errno); + } + message = vici_message_create_from_data(chunk_create(buf, len), TRUE); + + conn->mutex->lock(conn->mutex); + event = conn->events->get(conn->events, name); + if (event) + { + vici_res_t res = { + .message = message, + .enumerator = message->create_enumerator(message), + .strings = linked_list_create(), + }; + + event->cb(event->user, name, &res); + + res.enumerator->destroy(res.enumerator); + res.strings->destroy_function(res.strings, free); + } + conn->mutex->unlock(conn->mutex); + + message->destroy(message); + + return TRUE; +} + +CALLBACK(on_read, bool, + vici_conn_t *conn, stream_t *stream) +{ + u_int32_t len; + u_int8_t op; + ssize_t hlen; + + hlen = stream->read(stream, &len, sizeof(len), FALSE); + if (hlen <= 0) + { + if (errno == EWOULDBLOCK) + { + return TRUE; + } + return read_error(conn, errno); + } + if (hlen < sizeof(len)) + { + if (!stream->read_all(stream, ((void*)&len) + hlen, sizeof(len) - hlen)) + { + return read_error(conn, errno); + } + } + + len = ntohl(len); + if (len > VICI_MESSAGE_SIZE_MAX) + { + return read_error(conn, EBADMSG); + } + if (len-- < sizeof(op)) + { + return read_error(conn, EBADMSG); + } + if (!stream->read_all(stream, &op, sizeof(op))) + { + return read_error(conn, errno); + } + switch (op) + { + case VICI_EVENT: + return handle_event(conn, len); + case VICI_CMD_RESPONSE: + return handle_response(conn, len); + case VICI_EVENT_CONFIRM: + return wait_result(conn, WAIT_SUCCESS); + case VICI_CMD_UNKNOWN: + case VICI_EVENT_UNKNOWN: + return wait_result(conn, WAIT_FAILURE); + case VICI_CMD_REQUEST: + case VICI_EVENT_REGISTER: + case VICI_EVENT_UNREGISTER: + default: + return read_error(conn, EBADMSG); + } +} + +vici_conn_t* vici_connect(char *uri) +{ + vici_conn_t *conn; + stream_t *stream; + + stream = lib->streams->connect(lib->streams, uri ?: VICI_DEFAULT_URI); + if (!stream) + { + return NULL; + } + + INIT(conn, + .stream = stream, + .events = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .cond = condvar_create(CONDVAR_TYPE_DEFAULT), + ); + + stream->on_read(stream, on_read, conn); + + return conn; +} + +void vici_disconnect(vici_conn_t *conn) +{ + enumerator_t *enumerator; + event_t *event; + + conn->stream->destroy(conn->stream); + enumerator = conn->events->create_enumerator(conn->events); + while (enumerator->enumerate(enumerator, NULL, &event)) + { + free(event->name); + free(event); + } + enumerator->destroy(enumerator); + conn->events->destroy(conn->events); + conn->mutex->destroy(conn->mutex); + conn->cond->destroy(conn->cond); + free(conn); +} + +vici_req_t* vici_begin(char *name) +{ + vici_req_t *req; + + INIT(req, + .name = strdup(name), + .b = vici_builder_create(), + ); + + return req; +} + +void vici_begin_section(vici_req_t *req, char *name) +{ + req->b->add(req->b, VICI_SECTION_START, name); +} + +void vici_end_section(vici_req_t *req) +{ + req->b->add(req->b, VICI_SECTION_END); +} + +void vici_add_key_value(vici_req_t *req, char *key, void *buf, int len) +{ + req->b->add(req->b, VICI_KEY_VALUE, key, chunk_create(buf, len)); +} + +void vici_add_key_valuef(vici_req_t *req, char *key, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + req->b->vadd_kv(req->b, key, fmt, args); + va_end(args); +} + +void vici_begin_list(vici_req_t *req, char *name) +{ + req->b->add(req->b, VICI_LIST_START, name); +} + +void vici_add_list_item(vici_req_t *req, void *buf, int len) +{ + req->b->add(req->b, VICI_LIST_ITEM, chunk_create(buf, len)); +} + +void vici_add_list_itemf(vici_req_t *req, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + req->b->vadd_li(req->b, fmt, args); + va_end(args); +} + +void vici_end_list(vici_req_t *req) +{ + req->b->add(req->b, VICI_LIST_END); +} + +vici_res_t* vici_submit(vici_req_t *req, vici_conn_t *conn) +{ + vici_message_t *message; + vici_res_t *res; + chunk_t data; + u_int32_t len; + u_int8_t namelen, op; + + message = req->b->finalize(req->b); + if (!message) + { + errno = EINVAL; + return NULL; + } + + op = VICI_CMD_REQUEST; + namelen = strlen(req->name); + data = message->get_encoding(message); + len = htonl(sizeof(op) + sizeof(namelen) + namelen + data.len); + + if (!conn->stream->write_all(conn->stream, &len, sizeof(len)) || + !conn->stream->write_all(conn->stream, &op, sizeof(op)) || + !conn->stream->write_all(conn->stream, &namelen, sizeof(namelen)) || + !conn->stream->write_all(conn->stream, req->name, namelen) || + !conn->stream->write_all(conn->stream, data.ptr, data.len)) + { + free(req->name); + free(req); + message->destroy(message); + return NULL; + } + free(req->name); + free(req); + message->destroy(message); + + message = NULL; + conn->mutex->lock(conn->mutex); + while (conn->wait == WAIT_IDLE) + { + conn->cond->wait(conn->cond, conn->mutex); + } + switch (conn->wait) + { + case WAIT_SUCCESS: + message = vici_message_create_from_data(conn->queue, TRUE); + conn->queue = chunk_empty; + break; + case WAIT_READ_ERROR: + errno = conn->error; + break; + case WAIT_FAILURE: + default: + errno = ENOENT; + break; + } + conn->wait = WAIT_IDLE; + conn->mutex->unlock(conn->mutex); + + conn->stream->on_read(conn->stream, on_read, conn); + + if (message) + { + INIT(res, + .message = message, + .enumerator = message->create_enumerator(message), + .strings = linked_list_create(), + ); + return res; + } + return NULL; +} + +void vici_free_req(vici_req_t *req) +{ + vici_message_t *message; + + free(req->name); + message = req->b->finalize(req->b); + if (message) + { + message->destroy(message); + } + free(req); +} + +int vici_dump(vici_res_t *res, char *label, bool pretty, FILE *out) +{ + if (res->message->dump(res->message, label, pretty, out)) + { + return 0; + } + errno = EBADMSG; + return 1; +} + +vici_parse_t vici_parse(vici_res_t *res) +{ + if (!res->enumerator->enumerate(res->enumerator, + &res->type, &res->name, &res->value)) + { + return VICI_PARSE_ERROR; + } + switch (res->type) + { + case VICI_END: + return VICI_PARSE_END; + case VICI_SECTION_START: + return VICI_PARSE_BEGIN_SECTION; + case VICI_SECTION_END: + return VICI_PARSE_END_SECTION; + case VICI_LIST_START: + return VICI_PARSE_BEGIN_LIST; + case VICI_LIST_ITEM: + return VICI_PARSE_LIST_ITEM; + case VICI_LIST_END: + return VICI_PARSE_END_LIST; + case VICI_KEY_VALUE: + return VICI_PARSE_KEY_VALUE; + default: + return VICI_PARSE_ERROR; + } +} + +char* vici_parse_name(vici_res_t *res) +{ + char *name; + + switch (res->type) + { + case VICI_SECTION_START: + case VICI_LIST_START: + case VICI_KEY_VALUE: + name = strdup(res->name); + res->strings->insert_last(res->strings, name); + return name; + default: + errno = EINVAL; + return NULL; + } +} + +int vici_parse_name_eq(vici_res_t *res, char *name) +{ + switch (res->type) + { + case VICI_SECTION_START: + case VICI_LIST_START: + case VICI_KEY_VALUE: + return streq(name, res->name) ? 1 : 0; + default: + return 0; + } +} + +void* vici_parse_value(vici_res_t *res, int *len) +{ + switch (res->type) + { + case VICI_LIST_ITEM: + case VICI_KEY_VALUE: + *len = res->value.len; + return res->value.ptr; + default: + *len = 0; + errno = EINVAL; + return NULL; + } +} + +char* vici_parse_value_str(vici_res_t *res) +{ + char *val; + + switch (res->type) + { + case VICI_LIST_ITEM: + case VICI_KEY_VALUE: + if (!chunk_printable(res->value, NULL, 0)) + { + errno = EBADMSG; + return NULL; + } + val = strndup(res->value.ptr, res->value.len); + res->strings->insert_last(res->strings, val); + return val; + default: + errno = EINVAL; + return NULL; + } +} + +int vici_parse_cb(vici_res_t *res, vici_parse_section_cb_t section, + vici_parse_value_cb_t kv, vici_parse_value_cb_t li, + void *user) +{ + char *name, *list = NULL; + void *value; + int base, len, ret; + + base = res->level; + + while (TRUE) + { + switch (vici_parse(res)) + { + case VICI_PARSE_KEY_VALUE: + if (res->level == base) + { + if (kv) + { + name = vici_parse_name(res); + value = vici_parse_value(res, &len); + if (name && value) + { + ret = kv(user, res, name, value, len); + if (ret) + { + return ret; + } + } + } + } + break; + case VICI_PARSE_BEGIN_SECTION: + if (res->level++ == base) + { + if (section) + { + name = vici_parse_name(res); + if (name) + { + ret = section(user, res, name); + if (ret) + { + return ret; + } + } + } + } + break; + case VICI_PARSE_END_SECTION: + if (res->level-- == base) + { + return 0; + } + break; + case VICI_PARSE_END: + res->level = 0; + return 0; + case VICI_PARSE_BEGIN_LIST: + if (res->level == base) + { + list = vici_parse_name(res); + } + break; + case VICI_PARSE_LIST_ITEM: + if (list && li) + { + value = vici_parse_value(res, &len); + if (value) + { + ret = li(user, res, list, value, len); + if (ret) + { + return ret; + } + } + } + break; + case VICI_PARSE_END_LIST: + if (res->level == base) + { + list = NULL; + } + break; + case VICI_PARSE_ERROR: + res->level = 0; + errno = EBADMSG; + return 1; + } + } +} + +void* vici_find(vici_res_t *res, int *len, char *fmt, ...) +{ + va_list args; + chunk_t value; + + va_start(args, fmt); + value = res->message->vget_value(res->message, chunk_empty, fmt, args); + va_end(args); + + *len = value.len; + return value.ptr; +} + +char* vici_find_str(vici_res_t *res, char *def, char *fmt, ...) +{ + va_list args; + char *str; + + va_start(args, fmt); + str = res->message->vget_str(res->message, def, fmt, args); + va_end(args); + + return str; +} + +int vici_find_int(vici_res_t *res, int def, char *fmt, ...) +{ + va_list args; + int val; + + va_start(args, fmt); + val = res->message->vget_int(res->message, def, fmt, args); + va_end(args); + + return val; +} + +void vici_free_res(vici_res_t *res) +{ + res->strings->destroy_function(res->strings, free); + res->message->destroy(res->message); + res->enumerator->destroy(res->enumerator); + free(res); +} + +int vici_register(vici_conn_t *conn, char *name, vici_event_cb_t cb, void *user) +{ + event_t *event; + u_int32_t len; + u_int8_t namelen, op; + int ret = 1; + + op = cb ? VICI_EVENT_REGISTER : VICI_EVENT_UNREGISTER; + namelen = strlen(name); + len = htonl(sizeof(op) + sizeof(namelen) + namelen); + if (!conn->stream->write_all(conn->stream, &len, sizeof(len)) || + !conn->stream->write_all(conn->stream, &op, sizeof(op)) || + !conn->stream->write_all(conn->stream, &namelen, sizeof(namelen)) || + !conn->stream->write_all(conn->stream, name, namelen)) + { + return 1; + } + + conn->mutex->lock(conn->mutex); + while (conn->wait == WAIT_IDLE) + { + conn->cond->wait(conn->cond, conn->mutex); + } + switch (conn->wait) + { + case WAIT_SUCCESS: + ret = 0; + break; + case WAIT_READ_ERROR: + errno = conn->error; + break; + case WAIT_FAILURE: + default: + errno = ENOENT; + break; + } + conn->wait = WAIT_IDLE; + conn->mutex->unlock(conn->mutex); + + conn->stream->on_read(conn->stream, on_read, conn); + + if (ret == 0) + { + conn->mutex->lock(conn->mutex); + if (cb) + { + INIT(event, + .name = strdup(name), + .cb = cb, + .user = user, + ); + event = conn->events->put(conn->events, event->name, event); + } + else + { + event = conn->events->remove(conn->events, name); + } + conn->mutex->unlock(conn->mutex); + + if (event) + { + free(event->name); + free(event); + } + } + return ret; +} + +void vici_init() +{ + library_init(NULL, "vici"); + if (lib->processor->get_total_threads(lib->processor) < 4) + { + lib->processor->set_threads(lib->processor, 4); + } +} + +void vici_deinit() +{ + library_deinit(); +} diff --git a/src/libcharon/plugins/vici/libvici.h b/src/libcharon/plugins/vici/libvici.h new file mode 100644 index 000000000..58595d8cc --- /dev/null +++ b/src/libcharon/plugins/vici/libvici.h @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup libvici libvici + * @{ @ingroup vici + * + * libvici is a low-level client library for the "Versatile IKE Control + * Interface" protocol. While it uses libstrongswan and its thread-pool for + * asynchronous message delivery, this interface does not directly depend on + * libstrongswan interfaces and should be stable. + * + * This interface provides the following basic functions: + * + * - vici_init()/vici_deinit(): Library initialization functions + * - vici_connect(): Connect to a vici service + * - vici_disconnect(): Disconnect from a vici service + * + * Library initialization implicitly initializes libstrongswan and a small + * thread pool. + * + * Connecting requires an uri, which is currently either a UNIX socket path + * prefixed with unix://, or a hostname:port touple prefixed with tcp://. + * Passing NULL takes the system default socket path. + * + * After the connection has been established, request messages can be sent. + * Only a single thread may operate on a single connection instance + * simultaneously. To construct request messages, use the following functions: + * + * - vici_add_key_value() / vici_add_key_valuef(): Add key/value pairs + * - vici_begin(): Start constructing a new request message + * - vici_begin_section(): Open a new section to add contents to + * - vici_end_section(): Close a previously opened session + * - vici_begin_list(): Open a new list to add list items to + * - vici_end_list(): Close a previously opened list + * - vici_add_list_item() / vici_add_list_itemf(): Add list item + * + * Once the request message is complete, it can be sent or cancelled with: + * + * - vici_submit() + * - vici_free_req() + * + * If submitting a message is successful, a response message is returned. It + * can be processed using the following functions: + * + * - vici_parse(): Parse content type + * - vici_parse_name(): Parse name if content type provides one + * - vici_parse_name_eq(): Parse name and check if matches string + * - vici_parse_value() / vici_parse_value_str(): Parse value for content type + * - vici_dump(): Dump a full response to a FILE stream + * - vici_free_res(): Free response after use + * + * Usually vici_parse() is called in a loop, and depending on the returned + * type the name and value can be inspected. + * + * To register or unregister for asynchronous event messages vici_register() is + * used. The registered callback gets invoked by an asynchronous thread. To + * parse the event message, the vici_parse*() functions can be used. + */ + +#ifndef LIBVICI_H_ +#define LIBVICI_H_ + +#include <stdio.h> + +#include <utils/utils.h> + +/** + * Opaque vici connection contex. + */ +typedef struct vici_conn_t vici_conn_t; + +/** + * Opaque vici request message. + */ +typedef struct vici_req_t vici_req_t; + +/** + * Opaque vici response/event message. + */ +typedef struct vici_res_t vici_res_t; + +/** + * Vici parse result, as returned by vici_parse(). + */ +typedef enum { + /** encountered a section start, has a name */ + VICI_PARSE_BEGIN_SECTION, + /** encountered a section end */ + VICI_PARSE_END_SECTION, + /** encountered a list start, has a name */ + VICI_PARSE_BEGIN_LIST, + /** encountered a list element, has a value */ + VICI_PARSE_LIST_ITEM, + /** encountered a list end */ + VICI_PARSE_END_LIST, + /** encountered a key/value pair, has a name and a value */ + VICI_PARSE_KEY_VALUE, + /** encountered valid end of message */ + VICI_PARSE_END, + /** parse error */ + VICI_PARSE_ERROR, +} vici_parse_t; + +/** + * Callback function invoked for received event messages. + * + * It is not allowed to call vici_submit() from this callback. + * + * @param user user data, as passed to vici_connect + * @param name name of received event + * @param msg associated event message, destroyed by libvici + */ +typedef void (*vici_event_cb_t)(void *user, char *name, vici_res_t *msg); + +/** + * Callback function for key/value and list items, invoked by vici_parse_cb(). + * + * @param user user data, as passed to vici_parse_cb() + * @param res message currently parsing + * @param name name of key or list + * @param value value buffer + * @param len length of value buffer + * @return 0 if parsed successfully + */ +typedef int (*vici_parse_value_cb_t)(void *user, vici_res_t *res, char *name, + void *value, int len); + +/** + * Callback function for sections, invoked by vici_parse_cb(). + * + * @param user user data, as passed to vici_parse_cb() + * @param res message currently parsing + * @param name name of the section + * @return 0 if parsed successfully + */ +typedef int (*vici_parse_section_cb_t)(void *user, vici_res_t *res, char *name); + +/** + * Open a new vici connection. + * + * On error, NULL is returned and errno is set appropriately. + * + * @param uri URI to connect to, NULL to use system default + * @return opaque vici connection context, NULL on error + */ +vici_conn_t* vici_connect(char *uri); + +/** + * Close a vici connection. + * + * @param conn connection context + */ +void vici_disconnect(vici_conn_t *conn); + +/** + * Begin a new vici message request. + * + * This function always succeeds. + * + * @param name name of request command + * @return request message, to add contents + */ +vici_req_t* vici_begin(char *name); + +/** + * Begin a new section in a vici request message. + * + * @param req request message to create a new section in + * @param name name of section to create + */ +void vici_begin_section(vici_req_t *req, char *name); + +/** + * End a previously opened section. + * + * @param req request message to close an open section in + */ +void vici_end_section(vici_req_t *req); + +/** + * Add a key/value pair, using an as-is blob as value. + * + * @param req request message to add key/value pair to + * @param key key name of key/value pair + * @param buf pointer to blob to add as value + * @param len length of value blob to add + */ +void vici_add_key_value(vici_req_t *req, char *key, void *buf, int len); + +/** + * Add a key/value pair, setting value from a printf() format string. + * + * @param req request message to add key/value pair to + * @param key key name of key/value pair + * @param fmt format string for value + * @param ... arguments to format string + */ +void vici_add_key_valuef(vici_req_t *req, char *key, char *fmt, ...); + +/** + * Begin a list in a request message. + * + * After starting a list, only list items can be added until the list gets + * closed by vici_end_list(). + * + * @param req request message to begin list in + * @param name name of list to begin + */ +void vici_begin_list(vici_req_t *req, char *name); + +/** + * Add a list item to a currently open list, using an as-is blob. + * + * @param req request message to add list item to + * @param buf pointer to blob to add as value + * @param len length of value blob to add + */ +void vici_add_list_item(vici_req_t *req, void *buf, int len); + +/** + * Add a list item to a currently open list, using a printf() format string. + * + * @param req request message to add list item to + * @param fmt format string to create value from + * @param ... arguments to format string + */ +void vici_add_list_itemf(vici_req_t *req, char *fmt, ...); + +/** + * End a previously opened list in a request message. + * + * @param req request message to end list in + */ +void vici_end_list(vici_req_t *req); + +/** + * Submit a request message, and wait for response. + * + * The request messages gets cleaned up by this call and gets invalid. + * On error, NULL is returned an errno is set to: + * - EINVAL if the request is invalid/incomplete + * - ENOENT if the command is unknown + * - EBADMSG if the response is invalid + * - Any other IO related errno + * + * @param req request message to send + * @param conn connection context to send message over + * @return response message, NULL on error + */ +vici_res_t* vici_submit(vici_req_t *req, vici_conn_t *conn); + +/** + * Cancel a request message started. + * + * If a request created by vici_begin() does not get submitted using + * vici_submit(), it has to get freed using this call. + * + * @param req request message to clean up + */ +void vici_free_req(vici_req_t *req); + +/** + * Dump a message text representation to a FILE stream. + * + * On error, errno is set to: + * - EBADMSG if the message is invalid + * + * @param res response message to dump + * @param label a label to print for this message + * @param pretty use pretty print with indentation + * @param out FILE to dump to + * @return 0 if dumped complete message, 1 on error + */ +int vici_dump(vici_res_t *res, char *label, bool pretty, FILE *out); + +/** + * Parse next element from a vici response message. + * + * @param res response message to parse + * @return parse result + */ +vici_parse_t vici_parse(vici_res_t *res); + +/** + * Parse name tag / key of a previously parsed element. + * + * This call is valid only after vici_parse() returned VICI_PARSE_KEY_VALUE, + * VICI_PARSE_BEGIN_SECTION or VICI_PARSE_BEGIN_LIST. + * + * The string is valid until vici_free_res() is called. + * + * On error, errno is set to: + *- EINVAL if not in valid parser state + * + * @param res response message to parse + * @return name tag / key, NULL on error + */ +char* vici_parse_name(vici_res_t *res); + +/** + * Compare name tag / key of a previusly parsed element. + * + * This call is valid only after vici_parse() returned VICI_PARSE_KEY_VALUE, + * VICI_PARSE_BEGIN_SECTION or VICI_PARSE_BEGIN_LIST. + * + * @param res response message to parse + * @param name string to compare + * @return 1 if name equals, 0 if not + */ +int vici_parse_name_eq(vici_res_t *res, char *name); + +/** + * Parse value of a previously parsed element, as a blob. + * + * This call is valid only after vici_parse() returned VICI_PARSE_KEY_VALUE or + * VICI_PARSE_LIST_ITEM. + * + * The string is valid until vici_free_res() is called. + * + * On error, errno is set to: + * - EINVAL if not in valid parser state + * + * @param res response message to parse + * @param len pointer receiving value length + * @return pointer to value, NULL on error + */ +void* vici_parse_value(vici_res_t *res, int *len); + +/** + * Parse value of a previously parsed element, as a string. + * + * This call is valid only after vici_parse() returned VICI_PARSE_KEY_VALUE or + * VICI_PARSE_LIST_ITEM. + * + * This call is successful only if the value contains no non-printable + * characters. The string is valid until vici_free_res() is called. + * + * On error, errno is set to: + * - EBADMSG if value is not a printable string + * - EINVAL if not in valid parser state + * + * @param res response message to parse + * @return value as string, NULL on error + */ +char* vici_parse_value_str(vici_res_t *res); + +/** + * Parse a complete message with callbacks. + * + * Any of the callbacks may be NULL to skip this kind of item. Callbacks are + * invoked for the current section level only. To descent into sections, call + * vici_parse_cb() from within a section callback. + * + * On error, errno is set to: + * - EBADMSG if message encoding invalid + * - Any other errno set by the invoked callbacks + * + * @param res message to parse + * @param section callback invoked for each section + * @param kv callback invoked for key/value pairs + * @param li callback invoked for list items + * @param user user data to pass to callbacks + * @return 0 if parsing successful + */ +int vici_parse_cb(vici_res_t *res, vici_parse_section_cb_t section, + vici_parse_value_cb_t kv, vici_parse_value_cb_t li, + void *user); + +/* + * Find a blob value in a message for a given key. + * + * Sections can be selected by prefixing them separated by dots. + * + * @param res response message to parse + * @param len length of returned object + * @param fmt printf format string of key and sections + * @param ... arguments to format string + * @return blob value, having *len bytes, NULL if not found + */ +void *vici_find(vici_res_t *res, int *len, char *fmt, ...); + +/** + * Find a string value in a message for a given key. + * + * Sections can be selected by prefixing them separated by dots. + * + * @param res response message to parse + * @param def default value, if key not found + * @param fmt printf format string of key and sections + * @param ... arguments to format string + * @return string, def if not found + */ +char* vici_find_str(vici_res_t *res, char *def, char *fmt, ...); + +/** + * Find an integer value in a message for a given key. + * + * Sections can be selected by prefixing them separated by dots. + * + * @param res response message to parse + * @param def default value, if key not found + * @param fmt printf format string of key and sections + * @param ... arguments to format string + * @return integer value, def if not found + */ +int vici_find_int(vici_res_t *res, int def, char *fmt, ...); + +/** + * Clean up a received response message. + * + * Event messages get cleaned up by the library, it is not allowed to call + * vici_free_res() from within a vici_event_cb_t. + * + * @param res response message to free + */ +void vici_free_res(vici_res_t *res); + +/** + * (Un-)Register for events of a given kind. + * + * Events callbacks get invoked by a different thread from the libstrongswan + * thread pool. + * On failure, errno is set to: + * - ENOENT if the event name is unknown + * - EBADMSG if the response is invalid + * - Any other IO related errno + * + * @param conn connection context + * @param name name of event messages to register to + * @param cb callback function to register, NULL to unregister + * @param user user data passed to callback invocations + * @return 0 if registered successfully + */ +int vici_register(vici_conn_t *conn, char *name, vici_event_cb_t cb, void *user); + +/** + * Initialize libvici before first time use. + */ +void vici_init(); + +/** + * Deinitialize libvici after use. + */ +void vici_deinit(); + +#endif /** LIBVICI_H_ @}*/ diff --git a/src/libcharon/plugins/vici/suites/test_event.c b/src/libcharon/plugins/vici/suites/test_event.c new file mode 100644 index 000000000..b923ad393 --- /dev/null +++ b/src/libcharon/plugins/vici/suites/test_event.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <test_suite.h> + +#include "../vici_dispatcher.h" +#include "../libvici.h" + +#include <unistd.h> + +#ifdef WIN32 +# define URI "tcp://127.0.0.1:6543" +#else /* !WIN32 */ +# define URI "unix:///tmp/strongswan-vici-event-test" +#endif /* !WIN32 */ + +static void event_cb(void *user, char *name, vici_res_t *ev) +{ + int *count = (int*)user; + + ck_assert_str_eq(name, "test"); + ck_assert(vici_parse(ev) == VICI_PARSE_KEY_VALUE); + ck_assert_str_eq(vici_parse_name(ev), "key1"); + ck_assert_str_eq(vici_parse_value_str(ev), "value1"); + ck_assert(vici_parse(ev) == VICI_PARSE_END); + + (*count)++; +} + +START_TEST(test_event) +{ + vici_dispatcher_t *dispatcher; + vici_conn_t *conn; + int count = 0; + + lib->processor->set_threads(lib->processor, 8); + + dispatcher = vici_dispatcher_create(URI); + ck_assert(dispatcher); + + dispatcher->manage_event(dispatcher, "test", TRUE); + + vici_init(); + conn = vici_connect(URI); + ck_assert(conn); + + ck_assert(vici_register(conn, "test", event_cb, &count) == 0); + ck_assert(vici_register(conn, "nonexistent", event_cb, &count) != 0); + + dispatcher->raise_event(dispatcher, "test", 0, vici_message_create_from_args( + VICI_KEY_VALUE, "key1", chunk_from_str("value1"), + VICI_END)); + + while (count == 0) + { + usleep(1000); + } + + vici_disconnect(conn); + + dispatcher->manage_event(dispatcher, "test", FALSE); + + lib->processor->cancel(lib->processor); + dispatcher->destroy(dispatcher); + + vici_deinit(); +} +END_TEST + +#define EVENT_COUNT 500 + +CALLBACK(raise_cb, vici_message_t*, + vici_dispatcher_t *dispatcher, char *name, u_int id, vici_message_t *req) +{ + u_int i; + + for (i = 0; i < EVENT_COUNT; i++) + { + dispatcher->raise_event(dispatcher, "event", id, + vici_message_create_from_args( + VICI_KEY_VALUE, "counter", chunk_from_thing(i), + VICI_END)); + } + return vici_message_create_from_args(VICI_END); +} + +CALLBACK(raise_event_cb, void, + int *count, char *name, vici_res_t *ev) +{ + u_int *value, len; + + ck_assert_str_eq(name, "event"); + ck_assert(vici_parse(ev) == VICI_PARSE_KEY_VALUE); + ck_assert_str_eq(vici_parse_name(ev), "counter"); + value = vici_parse_value(ev, &len); + ck_assert_int_eq(len, sizeof(*value)); + ck_assert(vici_parse(ev) == VICI_PARSE_END); + + ck_assert_int_eq(*count, *value); + (*count)++; +} + +START_TEST(test_raise_events) +{ + vici_dispatcher_t *dispatcher; + vici_res_t *res; + vici_conn_t *conn; + int count = 0; + + lib->processor->set_threads(lib->processor, 8); + + dispatcher = vici_dispatcher_create(URI); + ck_assert(dispatcher); + + dispatcher->manage_event(dispatcher, "event", TRUE); + dispatcher->manage_command(dispatcher, "raise", raise_cb, dispatcher); + + vici_init(); + conn = vici_connect(URI); + ck_assert(conn); + + ck_assert(vici_register(conn, "event", raise_event_cb, &count) == 0); + + res = vici_submit(vici_begin("raise"), conn); + + ck_assert_int_eq(count, EVENT_COUNT); + ck_assert(res); + vici_free_res(res); + + vici_disconnect(conn); + + dispatcher->manage_event(dispatcher, "event", FALSE); + dispatcher->manage_command(dispatcher, "raise", NULL, NULL); + + lib->processor->cancel(lib->processor); + dispatcher->destroy(dispatcher); + + vici_deinit(); +} +END_TEST + +START_TEST(test_stress) +{ + vici_dispatcher_t *dispatcher; + vici_conn_t *conn; + int count = 0, i, total = 50; + + lib->processor->set_threads(lib->processor, 8); + + dispatcher = vici_dispatcher_create(URI); + ck_assert(dispatcher); + + dispatcher->manage_event(dispatcher, "test", TRUE); + dispatcher->manage_event(dispatcher, "dummy", TRUE); + + vici_init(); + conn = vici_connect(URI); + ck_assert(conn); + + vici_register(conn, "test", event_cb, &count); + + for (i = 0; i < total; i++) + { + /* do some event re/deregistration in between */ + ck_assert(vici_register(conn, "dummy", event_cb, NULL) == 0); + + dispatcher->raise_event(dispatcher, "test", 0, + vici_message_create_from_args( + VICI_KEY_VALUE, "key1", chunk_from_str("value1"), + VICI_END)); + + ck_assert(vici_register(conn, "dummy", NULL, NULL) == 0); + } + + while (count < total) + { + usleep(1000); + } + + vici_disconnect(conn); + + dispatcher->manage_event(dispatcher, "test", FALSE); + dispatcher->manage_event(dispatcher, "dummy", FALSE); + + lib->processor->cancel(lib->processor); + dispatcher->destroy(dispatcher); + + vici_deinit(); +} +END_TEST + +Suite *event_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("vici events"); + + tc = tcase_create("single"); + tcase_add_test(tc, test_event); + suite_add_tcase(s, tc); + + tc = tcase_create("raise events"); + tcase_add_test(tc, test_raise_events); + suite_add_tcase(s, tc); + + tc = tcase_create("stress"); + tcase_add_test(tc, test_stress); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libcharon/plugins/vici/suites/test_message.c b/src/libcharon/plugins/vici/suites/test_message.c new file mode 100644 index 000000000..293117348 --- /dev/null +++ b/src/libcharon/plugins/vici/suites/test_message.c @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <test_suite.h> + +#include "../vici_message.h" +#include "../vici_builder.h" + +#include <unistd.h> + +static char blob[] = { + 0xd3,0xe5,0xee,0x37,0x7b,0x96,0x2f,0x3e,0x5f,0x3e,0x91,0xea,0x38,0x44,0xba,0x6c, + 0x75,0xc8,0x42,0x32,0xaf,0x7a,0x66,0x43,0x33,0x92,0xd2,0xef,0x7d,0x91,0x7b,0x59, + 0x9f,0x9f,0xd1,0x44,0xb6,0x1e,0x8c,0xd1,0xc5,0xa0,0xd9,0xe4,0xf2,0x31,0xfd,0x7b, + 0x5b,0x56,0xa7,0xfe,0x63,0x0d,0xcb,0x31,0x74,0xd8,0xd6,0x4a,0x42,0x3a,0x88,0xf3, + 0x79,0xf9,0x41,0xa6,0xc0,0x64,0x53,0x31,0x42,0xe2,0xd4,0x4a,0x22,0x5f,0x3f,0x99, + 0xe0,0x1a,0xcb,0x93,0x26,0xd0,0xec,0xac,0x90,0x97,0x0a,0x5f,0x69,0x86,0xf1,0xda, + 0xfc,0xa7,0xac,0xd0,0xd8,0x81,0xcf,0x7d,0x47,0x22,0xbe,0xbf,0x00,0x9b,0x6b,0x86, + 0x92,0x89,0xbe,0x7f,0x74,0x13,0x53,0xf1,0x4c,0x2b,0xc9,0xe1,0x39,0xd6,0xfc,0x50, + 0x3f,0x00,0xfb,0x76,0x42,0xa6,0xa4,0x70,0xfc,0x93,0x17,0x4a,0x35,0xce,0x5e,0x78, + 0x41,0x88,0x24,0x50,0x78,0xf2,0x38,0x08,0xff,0x40,0xef,0x61,0xbb,0xbf,0x16,0xff, + 0x0b,0xf6,0x33,0x21,0xcb,0x48,0xbd,0x7d,0xd1,0x73,0xfa,0x6d,0xd6,0xab,0xde,0x69, + 0x63,0x17,0xdb,0x52,0xe2,0x75,0x4b,0xb7,0x1e,0xf0,0x8a,0x55,0x4f,0x70,0x8d,0x18, + 0xe5,0x38,0x6a,0x9f,0xb8,0x06,0xb5,0x91,0x90,0x2b,0xc5,0x67,0xa9,0x12,0xe5,0xf3, + 0x48,0x2f,0x80,0x03,0xa1,0xa0,0xfc,0x43,0xe9,0x0f,0x83,0x2b,0xbc,0x7c,0xa8,0x3b, + 0x6c,0xc1,0xc8,0x72,0x5f,0x87,0x63,0x77,0x93,0x9b,0xe2,0xd7,0x4e,0xe6,0x65,0xa1, + 0x69,0x00,0xda,0xf8,0xb4,0x61,0xee,0xb7,0x20,0xe7,0x2a,0x35,0x23,0xf0,0x37,0x4b, + 0x67,0xcf,0x8d,0x85,0x72,0x22,0x6d,0x7a,0xb2,0x96,0xff,0x49,0xf4,0x94,0x3e,0x7e, + 0x87,0x26,0x5d,0x34,0x05,0x26,0x60,0x9b,0x89,0xfe,0xf9,0x91,0xd3,0x03,0xe7,0x8a, + 0x03,0xf6,0x4e,0xbf,0x68,0x13,0xc6,0xf2,0x7b,0x9c,0xe6,0x36,0x1b,0xe2,0x22,0x44, + 0xb1,0x19,0x34,0x5f,0xe8,0x44,0x48,0x3a,0x19,0xe4,0xbd,0xb0,0x4e,0xb5,0x2c,0x40, + 0x55,0x39,0xe6,0x4c,0xd5,0x68,0x34,0x72,0x6b,0x6d,0x88,0xce,0x7e,0x77,0x95,0x17, + 0x2e,0x68,0x3f,0x0e,0x9d,0x70,0x9a,0x22,0xfa,0x19,0xcc,0x15,0x9d,0xba,0xaa,0xec, + 0xb1,0x67,0x19,0x51,0xce,0x60,0x9a,0x38,0xf8,0xa7,0x4e,0xe3,0x25,0x47,0x1e,0x1d, + 0x30,0x76,0x91,0x8f,0x4d,0x13,0x59,0x06,0x2f,0x01,0x10,0x95,0xdb,0x08,0x7c,0x46, + 0xed,0x47,0xa1,0x19,0x4c,0x46,0xd1,0x3a,0x3f,0x88,0x7a,0x63,0xae,0x29,0x13,0x42, + 0xe9,0x17,0xe8,0xa9,0x95,0xfc,0xd1,0xea,0xfa,0x59,0x90,0xfe,0xb7,0xbb,0x7f,0x61, + 0x1b,0xcb,0x3d,0x12,0x99,0x96,0x3e,0x23,0x23,0xec,0x3a,0x4d,0x86,0x86,0x74,0xef, + 0x38,0xa6,0xdc,0x3a,0x83,0x85,0xf8,0xb8,0xad,0x5b,0x33,0x94,0x4d,0x0e,0x68,0xbc, + 0xf2,0xc7,0x6f,0x84,0x18,0x1e,0x5a,0x66,0x1f,0x6c,0x98,0x33,0xda,0xde,0x9e,0xda, + 0x82,0xd0,0x56,0x44,0x47,0x08,0x0c,0x07,0x81,0x9d,0x8b,0x64,0x16,0x73,0x9d,0x80, + 0x54,0x9c,0x4c,0x42,0xde,0x27,0x4e,0x97,0xb2,0xcf,0x48,0xaf,0x7e,0x85,0xc1,0xcd, + 0x6a,0x4d,0x04,0x40,0x89,0xa3,0x9d,0x4e,0x89,0x56,0x60,0x31,0x1f,0x3f,0x49,0x16, +}; + +typedef struct { + vici_type_t type; + char *name; + chunk_t data; +} endecode_test_t; + +static endecode_test_t endecode_test_simple[] = { + { VICI_SECTION_START, "section1", {} }, + { VICI_KEY_VALUE, "key1", { "value1", 6 } }, + { VICI_KEY_VALUE, "key2", { "value2", 6 } }, + { VICI_SECTION_END, NULL, {} }, + { VICI_END, NULL, {} }, +}; + +static endecode_test_t endecode_test_nested[] = { + { VICI_SECTION_START, "section1", {} }, + { VICI_SECTION_START, "section2", {} }, + { VICI_SECTION_START, "section3", {} }, + { VICI_KEY_VALUE, "key1", { "value1", 6 } }, + { VICI_SECTION_START, "section4", {} }, + { VICI_KEY_VALUE, "key2", { "value2", 6 } }, + { VICI_SECTION_END, NULL, {} }, + { VICI_SECTION_END, NULL, {} }, + { VICI_SECTION_END, NULL, {} }, + { VICI_KEY_VALUE, "key3", { "value3", 6 } }, + { VICI_SECTION_END, NULL, {} }, + { VICI_END, NULL, {} }, +}; + +static endecode_test_t endecode_test_list[] = { + { VICI_SECTION_START, "section1", {} }, + { VICI_LIST_START, "list1", {} }, + { VICI_LIST_ITEM, NULL, { "item1", 5 } }, + { VICI_LIST_ITEM, NULL, { "item2", 5 } }, + { VICI_LIST_END, NULL, {} }, + { VICI_KEY_VALUE, "key1", { "value1", 6 } }, + { VICI_SECTION_END, NULL, {} }, + { VICI_END, NULL, {} }, +}; + +static endecode_test_t endecode_test_blobs[] = { + { VICI_KEY_VALUE, "key1", { blob, countof(blob) } }, + { VICI_SECTION_START, "section1", {} }, + { VICI_LIST_START, "list1", {} }, + { VICI_LIST_ITEM, NULL, { blob, countof(blob) } }, + { VICI_LIST_ITEM, NULL, { blob, countof(blob) } }, + { VICI_LIST_END, NULL, {} }, + { VICI_KEY_VALUE, "key2", { blob, countof(blob) } }, + { VICI_SECTION_END, NULL, {} }, + { VICI_END, NULL, {} }, +}; + +static endecode_test_t *endecode_tests[] = { + endecode_test_simple, + endecode_test_nested, + endecode_test_list, + endecode_test_blobs, +}; + +typedef struct { + enumerator_t public; + endecode_test_t *next; +} endecode_enum_t; + +static bool endecode_enumerate(endecode_enum_t *this, vici_type_t *type, + char **name, chunk_t *data) +{ + if (this->next) + { + *type = this->next->type; + *name = this->next->name; + *data = this->next->data; + if (this->next->type == VICI_END) + { + this->next = NULL; + } + else + { + this->next++; + } + return TRUE; + } + return FALSE; +} + +static enumerator_t *endecode_create_enumerator(endecode_test_t *test) +{ + endecode_enum_t *enumerator; + + INIT(enumerator, + .public = { + .enumerate = (void*)endecode_enumerate, + .destroy = (void*)free, + }, + .next = test, + ); + + return &enumerator->public; +} + +static void compare_vici(enumerator_t *parse, enumerator_t *tmpl) +{ + vici_type_t type, ttype; + char *name, *tname; + chunk_t data, tdata;; + + while (TRUE) + { + ck_assert(parse->enumerate(parse, &type, &name, &data)); + ck_assert(tmpl->enumerate(tmpl, &ttype, &tname, &tdata)); + ck_assert_int_eq(type, ttype); + switch (type) + { + case VICI_END: + return; + case VICI_SECTION_START: + case VICI_LIST_START: + ck_assert(streq(name, tname)); + break; + case VICI_LIST_ITEM: + ck_assert(chunk_equals(data, tdata)); + break; + case VICI_KEY_VALUE: + ck_assert(streq(name, tname)); + ck_assert(chunk_equals(data, tdata)); + break; + case VICI_SECTION_END: + case VICI_LIST_END: + break; + default: + ck_assert(FALSE); + break; + } + } +} + +START_TEST(test_endecode) +{ + enumerator_t *parse, *tmpl; + vici_message_t *m; + chunk_t data; + + tmpl = endecode_create_enumerator(endecode_tests[_i]); + m = vici_message_create_from_enumerator(tmpl); + ck_assert(m); + data = chunk_clone(m->get_encoding(m)); + tmpl = endecode_create_enumerator(endecode_tests[_i]); + parse = m->create_enumerator(m); + ck_assert(parse); + compare_vici(parse, tmpl); + tmpl->destroy(tmpl); + parse->destroy(parse); + m->destroy(m); + + m = vici_message_create_from_data(data, TRUE); + ck_assert(m); + tmpl = endecode_create_enumerator(endecode_tests[_i]); + parse = m->create_enumerator(m); + ck_assert(parse); + compare_vici(parse, tmpl); + tmpl->destroy(tmpl); + parse->destroy(parse); + m->destroy(m); +} +END_TEST + +START_TEST(test_vararg) +{ + enumerator_t *parse, *tmpl; + vici_message_t *m; + + m = vici_message_create_from_args( + VICI_SECTION_START, "section1", + VICI_LIST_START, "list1", + VICI_LIST_ITEM, chunk_from_str("item1"), + VICI_LIST_ITEM, chunk_from_str("item2"), + VICI_LIST_END, + VICI_KEY_VALUE, "key1", chunk_from_str("value1"), + VICI_SECTION_END, + VICI_END); + ck_assert(m); + tmpl = endecode_create_enumerator(endecode_test_list); + parse = m->create_enumerator(m); + ck_assert(parse); + + compare_vici(parse, tmpl); + + m->destroy(m); + tmpl->destroy(tmpl); + parse->destroy(parse); +} +END_TEST + +START_TEST(test_builder) +{ + enumerator_t *parse, *tmpl; + vici_message_t *m; + vici_builder_t *b; + + b = vici_builder_create(); + b->add(b, VICI_SECTION_START, "section1"); + b->add(b, VICI_LIST_START, "list1"); + b->add(b, VICI_LIST_ITEM, chunk_from_str("item1")); + b->add(b, VICI_LIST_ITEM, chunk_from_str("item2")); + b->add(b, VICI_LIST_END); + b->add(b, VICI_KEY_VALUE, "key1", chunk_from_str("value1")); + b->add(b, VICI_SECTION_END); + m = b->finalize(b); + ck_assert(m); + tmpl = endecode_create_enumerator(endecode_test_list); + parse = m->create_enumerator(m); + ck_assert(parse); + + compare_vici(parse, tmpl); + + m->destroy(m); + tmpl->destroy(tmpl); + parse->destroy(parse); +} +END_TEST + +START_TEST(test_builder_fmt) +{ + enumerator_t *parse, *tmpl; + vici_message_t *m; + vici_builder_t *b; + + b = vici_builder_create(); + b->begin_section(b, "section1"); + b->begin_list(b, "list1"); + b->add_li(b, "item%u", 1); + b->add_li(b, "%s%u", "item", 2); + b->end_list(b); + b->add_kv(b, "key1", "value%u", 1); + b->end_section(b); + m = b->finalize(b); + ck_assert(m); + tmpl = endecode_create_enumerator(endecode_test_list); + parse = m->create_enumerator(m); + ck_assert(parse); + + compare_vici(parse, tmpl); + + m->destroy(m); + tmpl->destroy(tmpl); + parse->destroy(parse); +} +END_TEST + +static vici_message_t* build_getter_msg() +{ + return vici_message_create_from_args( + VICI_KEY_VALUE, "key1", chunk_from_str("1"), + VICI_SECTION_START, "section1", + VICI_KEY_VALUE, "key2", chunk_from_str("0x12"), + VICI_SECTION_START, "section2", + VICI_KEY_VALUE, "key3", chunk_from_str("-1"), + VICI_SECTION_END, + VICI_KEY_VALUE, "key4", chunk_from_str("asdf"), + VICI_SECTION_END, + VICI_KEY_VALUE, "key5", chunk_from_str(""), + VICI_END); +} + +START_TEST(test_get_str) +{ + vici_message_t *m; + + m = build_getter_msg(); + + ck_assert_str_eq(m->get_str(m, "def", "key1"), "1"); + ck_assert_str_eq(m->get_str(m, "def", "section1.key2"), "0x12"); + ck_assert_str_eq(m->get_str(m, "def", "section%d.section2.key3", 1), "-1"); + ck_assert_str_eq(m->get_str(m, "def", "section1.key4"), "asdf"); + ck_assert_str_eq(m->get_str(m, "def", "key5"), ""); + ck_assert_str_eq(m->get_str(m, "no", "nonexistent"), "no"); + ck_assert_str_eq(m->get_str(m, "no", "n.o.n.e.x.i.s.t.e.n.t"), "no"); + + m->destroy(m); +} +END_TEST + +START_TEST(test_get_int) +{ + vici_message_t *m; + + m = build_getter_msg(); + + ck_assert_int_eq(m->get_int(m, 2, "key1"), 1); + ck_assert_int_eq(m->get_int(m, 2, "section1.key2"), 0x12); + ck_assert_int_eq(m->get_int(m, 2, "section1.section2.key3"), -1); + ck_assert_int_eq(m->get_int(m, 2, "section1.key4"), 2); + ck_assert_int_eq(m->get_int(m, 2, "key5"), 0); + ck_assert_int_eq(m->get_int(m, 2, "nonexistent"), 2); + ck_assert_int_eq(m->get_int(m, 2, "n.o.n.e.x.i.s.t.e.n.t"), 2); + + m->destroy(m); +} +END_TEST + +START_TEST(test_get_value) +{ + vici_message_t *m; + chunk_t d = chunk_from_chars('d','e','f'); + + m = build_getter_msg(); + + ck_assert_chunk_eq(m->get_value(m, d, "key1"), chunk_from_str("1")); + ck_assert_chunk_eq(m->get_value(m, d, "section1.key2"), chunk_from_str("0x12")); + ck_assert_chunk_eq(m->get_value(m, d, "section1.section2.key3"), chunk_from_str("-1")); + ck_assert_chunk_eq(m->get_value(m, d, "section1.key4"), chunk_from_str("asdf")); + ck_assert_chunk_eq(m->get_value(m, d, "key5"), chunk_empty); + ck_assert_chunk_eq(m->get_value(m, d, "nonexistent"), d); + ck_assert_chunk_eq(m->get_value(m, d, "n.o.n.e.x.i.s.t.e.n.t"), d); + + m->destroy(m); +} +END_TEST + +Suite *message_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("vici message"); + + tc = tcase_create("enumerator en/decode"); + tcase_add_loop_test(tc, test_endecode, 0, countof(endecode_tests)); + suite_add_tcase(s, tc); + + tc = tcase_create("vararg encode"); + tcase_add_test(tc, test_vararg); + suite_add_tcase(s, tc); + + tc = tcase_create("builder encode"); + tcase_add_test(tc, test_builder); + suite_add_tcase(s, tc); + + tc = tcase_create("builder format encode"); + tcase_add_test(tc, test_builder_fmt); + suite_add_tcase(s, tc); + + tc = tcase_create("convenience getters"); + tcase_add_test(tc, test_get_str); + tcase_add_test(tc, test_get_int); + tcase_add_test(tc, test_get_value); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libcharon/plugins/vici/suites/test_request.c b/src/libcharon/plugins/vici/suites/test_request.c new file mode 100644 index 000000000..8eeb37bc9 --- /dev/null +++ b/src/libcharon/plugins/vici/suites/test_request.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <test_suite.h> + +#include "../vici_dispatcher.h" +#include "../libvici.h" + +#include <unistd.h> + +#ifdef WIN32 +# define URI "tcp://127.0.0.1:6543" +#else /* !WIN32 */ +# define URI "unix:///tmp/strongswan-vici-request-test" +#endif /* !WIN32 */ + +static void encode_section(vici_req_t *req) +{ + vici_begin_section(req, "section1"); + vici_add_key_valuef(req, "key1", "value%u", 1); + vici_add_key_value(req, "key2", "value2", strlen("value2")); + vici_end_section(req); +} + +static void decode_section(vici_res_t *res) +{ + char *str; + int len; + + ck_assert(vici_parse(res) == VICI_PARSE_BEGIN_SECTION); + ck_assert_str_eq(vici_parse_name(res), "section1"); + ck_assert(vici_parse(res) == VICI_PARSE_KEY_VALUE); + ck_assert_str_eq(vici_parse_name(res), "key1"); + ck_assert_str_eq(vici_parse_value_str(res), "value1"); + ck_assert(vici_parse(res) == VICI_PARSE_KEY_VALUE); + ck_assert_str_eq(vici_parse_name(res), "key2"); + str = vici_parse_value(res, &len); + ck_assert(chunk_equals(chunk_from_str("value2"), chunk_create(str, len))); + ck_assert(vici_parse(res) == VICI_PARSE_END_SECTION); + ck_assert(vici_parse(res) == VICI_PARSE_END); +} + +static void encode_list(vici_req_t *req) +{ + vici_begin_list(req, "list1"); + vici_add_list_item(req, "item1", strlen("item1")); + vici_add_list_itemf(req, "item%u", 2); + vici_end_list(req); +} + +static void decode_list(vici_res_t *res) +{ + char *str; + int len; + + ck_assert(vici_parse(res) == VICI_PARSE_BEGIN_LIST); + ck_assert_str_eq(vici_parse_name(res), "list1"); + ck_assert(vici_parse(res) == VICI_PARSE_LIST_ITEM); + ck_assert_str_eq(vici_parse_value_str(res), "item1"); + ck_assert(vici_parse(res) == VICI_PARSE_LIST_ITEM); + str = vici_parse_value(res, &len); + ck_assert(chunk_equals(chunk_from_str("item2"), chunk_create(str, len))); + ck_assert(vici_parse(res) == VICI_PARSE_END_LIST); + ck_assert(vici_parse(res) == VICI_PARSE_END); +} + +static struct { + void (*encode)(vici_req_t* req); + void (*decode)(vici_res_t* res); +} echo_tests[] = { + { encode_section, decode_section }, + { encode_list, decode_list }, +}; + +static vici_message_t* echo_cb(void *user, char *name, + u_int id, vici_message_t *request) +{ + ck_assert_str_eq(name, "echo"); + ck_assert_int_eq((uintptr_t)user, 1); + + return vici_message_create_from_enumerator(request->create_enumerator(request)); +} + +START_TEST(test_echo) +{ + vici_dispatcher_t *dispatcher; + vici_conn_t *conn; + vici_req_t *req; + vici_res_t *res; + + lib->processor->set_threads(lib->processor, 8); + + dispatcher = vici_dispatcher_create(URI); + ck_assert(dispatcher); + + dispatcher->manage_command(dispatcher, "echo", echo_cb, (void*)(uintptr_t)1); + + vici_init(); + conn = vici_connect(URI); + ck_assert(conn); + + req = vici_begin("echo"); + echo_tests[_i].encode(req); + res = vici_submit(req, conn); + ck_assert(res); + echo_tests[_i].decode(res); + vici_free_res(res); + + vici_disconnect(conn); + + dispatcher->manage_command(dispatcher, "echo", NULL, NULL); + + lib->processor->cancel(lib->processor); + dispatcher->destroy(dispatcher); + + vici_deinit(); +} +END_TEST + +START_TEST(test_missing) +{ + vici_dispatcher_t *dispatcher; + vici_conn_t *conn; + vici_req_t *req; + vici_res_t *res; + + lib->processor->set_threads(lib->processor, 8); + + dispatcher = vici_dispatcher_create(URI); + ck_assert(dispatcher); + + vici_init(); + conn = vici_connect(URI); + ck_assert(conn); + + req = vici_begin("nonexistent"); + encode_section(req); + res = vici_submit(req, conn); + ck_assert(res == NULL); + + vici_disconnect(conn); + + dispatcher->manage_command(dispatcher, "echo", NULL, NULL); + + lib->processor->cancel(lib->processor); + dispatcher->destroy(dispatcher); + + vici_deinit(); +} +END_TEST + +static void event_cb(void *user, char *name, vici_res_t *ev) +{ + int *events = (int*)user; + + (*events)++; +} + +START_TEST(test_stress) +{ + vici_dispatcher_t *dispatcher; + vici_conn_t *conn; + vici_req_t *req; + vici_res_t *res; + int i, total = 50, events = 0; + + lib->processor->set_threads(lib->processor, 8); + + dispatcher = vici_dispatcher_create(URI); + ck_assert(dispatcher); + + dispatcher->manage_command(dispatcher, "echo", echo_cb, (void*)(uintptr_t)1); + dispatcher->manage_event(dispatcher, "dummy", TRUE); + + vici_init(); + conn = vici_connect(URI); + ck_assert(conn); + + for (i = 0; i < total; i++) + { + /* do some event management in between */ + ck_assert(vici_register(conn, "dummy", event_cb, &events) == 0); + dispatcher->raise_event(dispatcher, "dummy", 0, + vici_message_create_from_args( + VICI_KEY_VALUE, "key1", chunk_from_str("value1"), + VICI_END)); + + req = vici_begin("echo"); + encode_section(req); + res = vici_submit(req, conn); + ck_assert(res); + decode_section(res); + vici_free_res(res); + + ck_assert(vici_register(conn, "dummy", NULL, NULL) == 0); + } + + while (events < total) + { + usleep(1000); + } + + vici_disconnect(conn); + + dispatcher->manage_command(dispatcher, "echo", NULL, NULL); + dispatcher->manage_event(dispatcher, "dummy", FALSE); + + lib->processor->cancel(lib->processor); + dispatcher->destroy(dispatcher); + + vici_deinit(); +} +END_TEST + +Suite *request_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("vici request"); + + tc = tcase_create("echo"); + tcase_add_loop_test(tc, test_echo, 0, countof(echo_tests)); + suite_add_tcase(s, tc); + + tc = tcase_create("missing"); + tcase_add_test(tc, test_missing); + suite_add_tcase(s, tc); + + tc = tcase_create("stress"); + tcase_add_test(tc, test_stress); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libcharon/plugins/vici/suites/test_socket.c b/src/libcharon/plugins/vici/suites/test_socket.c new file mode 100644 index 000000000..8d545c6c1 --- /dev/null +++ b/src/libcharon/plugins/vici/suites/test_socket.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <test_suite.h> + +#include "../vici_socket.h" + +#include <unistd.h> + +typedef struct { + vici_socket_t *s; + int disconnect; + int bytes; + u_int id; +} test_data_t; + +static void echo_inbound(void *user, u_int id, chunk_t buf) +{ + test_data_t *data = user; + + ck_assert_int_eq(data->id, id); + /* count number of bytes, including the header */ + data->bytes += buf.len + sizeof(u_int32_t); + /* echo back data chunk */ + data->s->send(data->s, id, chunk_clone(buf)); +} + +static void echo_connect(void *user, u_int id) +{ + test_data_t *data = user; + + data->id = id; +} + +static void echo_disconnect(void *user, u_int id) +{ + test_data_t *data = user; + + ck_assert(id == data->id); + data->disconnect++; +} + +static struct { + char *uri; + u_int chunksize; +} echo_tests[] = { + { "tcp://127.0.0.1:6543", ~0 }, + { "tcp://127.0.0.1:6543", 1 }, + { "tcp://127.0.0.1:6543", 2 }, + { "tcp://127.0.0.1:6543", 3 }, + { "tcp://127.0.0.1:6543", 7 }, +#ifndef WIN32 + { "unix:///tmp/strongswan-tests-vici-socket", ~0 }, + { "unix:///tmp/strongswan-tests-vici-socket", 1 }, + { "unix:///tmp/strongswan-tests-vici-socket", 2 }, + { "unix:///tmp/strongswan-tests-vici-socket", 3 }, + { "unix:///tmp/strongswan-tests-vici-socket", 7 }, +#endif /* !WIN32 */ +}; + +START_TEST(test_echo) +{ + stream_t *c; + test_data_t data = {}; + chunk_t x, m = chunk_from_chars( + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01, 0x01, + 0x00,0x00,0x00,0x05, 0x11,0x12,0x13,0x14,0x15, + 0x00,0x00,0x00,0x0A, 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x02A, + ); + char buf[m.len]; + u_int32_t len; + + lib->processor->set_threads(lib->processor, 4); + + /* create socket, connect with stream */ + data.s = vici_socket_create(echo_tests[_i].uri, echo_inbound, echo_connect, + echo_disconnect, &data); + ck_assert(data.s != NULL); + c = lib->streams->connect(lib->streams, echo_tests[_i].uri); + ck_assert(c != NULL); + + /* write arbitrary chunks of messages blob depending on test */ + x = m; + while (x.len) + { + len = min(x.len, echo_tests[_i].chunksize); + ck_assert(c->write_all(c, x.ptr, len)); + x = chunk_skip(x, len); + } + + /* verify echo */ + ck_assert(c->read_all(c, buf, sizeof(buf))); + ck_assert(chunk_equals(m, chunk_from_thing(buf))); + + /* wait for completion */ + c->destroy(c); + while (data.disconnect != 1) + { + usleep(1000); + } + /* check that we got correct number of bytes/invocations */ + ck_assert_int_eq(data.bytes, m.len); + + data.s->destroy(data.s); +} +END_TEST + +Suite *socket_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("vici socket"); + + tc = tcase_create("echo"); + tcase_add_loop_test(tc, test_echo, 0, countof(echo_tests)); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libcharon/plugins/vici/vici_attribute.c b/src/libcharon/plugins/vici/vici_attribute.c new file mode 100644 index 000000000..2178116c9 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_attribute.c @@ -0,0 +1,713 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_attribute.h" +#include "vici_builder.h" + +#include <daemon.h> +#include <collections/hashtable.h> +#include <collections/array.h> +#include <threading/rwlock.h> +#include <attributes/mem_pool.h> + +typedef struct private_vici_attribute_t private_vici_attribute_t; + +/** + * private data of vici_attribute + */ +struct private_vici_attribute_t { + + /** + * public functions + */ + vici_attribute_t public; + + /** + * vici connection dispatcher + */ + vici_dispatcher_t *dispatcher; + + /** + * Configured pools, as char* => pool_t + */ + hashtable_t *pools; + + /** + * rwlock to lock access to pools + */ + rwlock_t *lock; +}; + +/** + * Single configuration attribute with type + */ +typedef struct { + /** type of attribute */ + configuration_attribute_type_t type; + /** attribute value */ + chunk_t value; +} attribute_t; + +/** + * Clean up an attribute + */ +static void attribute_destroy(attribute_t *attr) +{ + free(attr->value.ptr); + free(attr); +} + +/** + * Pool instances with associated attributes + */ +typedef struct { + /** in-memory virtual IP pool */ + mem_pool_t *vips; + /** configuration attributes, as attribute_t */ + array_t *attrs; +} pool_t; + +/** + * Clean up a pool instance + */ +static void pool_destroy(pool_t *pool) +{ + DESTROY_IF(pool->vips); + array_destroy_function(pool->attrs, (void*)attribute_destroy, NULL); + free(pool); +} + +/** + * Find an existing or not yet existing lease + */ +static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools, + identification_t *id, host_t *requested, mem_pool_op_t op) +{ + enumerator_t *enumerator; + host_t *addr = NULL; + pool_t *pool; + char *name; + + enumerator = pools->create_enumerator(pools); + while (enumerator->enumerate(enumerator, &name)) + { + pool = this->pools->get(this->pools, name); + if (pool) + { + addr = pool->vips->acquire_address(pool->vips, id, requested, op); + if (addr) + { + break; + } + } + } + enumerator->destroy(enumerator); + + return addr; +} + +METHOD(attribute_provider_t, acquire_address, host_t*, + private_vici_attribute_t *this, linked_list_t *pools, identification_t *id, + host_t *requested) +{ + host_t *addr; + + this->lock->read_lock(this->lock); + + addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING); + if (!addr) + { + addr = find_addr(this, pools, id, requested, MEM_POOL_NEW); + if (!addr) + { + addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN); + } + } + + this->lock->unlock(this->lock); + + return addr; +} + +METHOD(attribute_provider_t, release_address, bool, + private_vici_attribute_t *this, linked_list_t *pools, host_t *address, + identification_t *id) +{ + enumerator_t *enumerator; + bool found = FALSE; + pool_t *pool; + char *name; + + this->lock->read_lock(this->lock); + + enumerator = pools->create_enumerator(pools); + while (enumerator->enumerate(enumerator, &name)) + { + pool = this->pools->get(this->pools, name); + if (pool) + { + found = pool->vips->release_address(pool->vips, address, id); + if (found) + { + break; + } + } + } + enumerator->destroy(enumerator); + + this->lock->unlock(this->lock); + + return found; +} + +/** + * Filter mapping attribute_t to enumerated type/value arguments + */ +static bool attr_filter(void *data, attribute_t **attr, + configuration_attribute_type_t *type, + void *in, chunk_t *value) +{ + *type = (*attr)->type; + *value = (*attr)->value; + return TRUE; +} + +/** + * Create nested inner enumerator over pool attributes + */ +CALLBACK(create_nested, enumerator_t*, + pool_t *pool, void *this) +{ + return enumerator_create_filter(array_create_enumerator(pool->attrs), + (void*)attr_filter, NULL, NULL); +} + +/** + * Data associated to nested enumerator cleanup + */ +typedef struct { + private_vici_attribute_t *this; + linked_list_t *list; +} nested_data_t; + +/** + * Clean up nested enumerator data + */ +CALLBACK(nested_cleanup, void, + nested_data_t *data) +{ + data->this->lock->unlock(data->this->lock); + data->list->destroy(data->list); + free(data); +} + +/** + * Check if any of vips is from pool + */ +static bool have_vips_from_pool(mem_pool_t *pool, linked_list_t *vips) +{ + enumerator_t *enumerator; + host_t *host; + chunk_t start, end, current; + u_int32_t size; + bool found = FALSE; + + host = pool->get_base(pool); + start = host->get_address(host); + + if (start.len >= sizeof(size)) + { + end = chunk_clone(start); + + /* mem_pool is currenty limited to 2^31 addresses, so 32-bit + * calculations should be sufficient. */ + size = untoh32(start.ptr + start.len - sizeof(size)); + htoun32(end.ptr + end.len - sizeof(size), size + pool->get_size(pool)); + + enumerator = vips->create_enumerator(vips); + while (enumerator->enumerate(enumerator, &host)) + { + current = host->get_address(host); + if (chunk_compare(current, start) >= 0 && + chunk_compare(current, end) < 0) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + free(end.ptr); + } + return found; +} + +METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, + private_vici_attribute_t *this, linked_list_t *pools, + identification_t *id, linked_list_t *vips) +{ + enumerator_t *enumerator; + nested_data_t *data; + pool_t *pool; + char *name; + + INIT(data, + .this = this, + .list = linked_list_create(), + ); + + this->lock->read_lock(this->lock); + + enumerator = pools->create_enumerator(pools); + while (enumerator->enumerate(enumerator, &name)) + { + pool = this->pools->get(this->pools, name); + if (pool && have_vips_from_pool(pool->vips, vips)) + { + data->list->insert_last(data->list, pool); + } + } + enumerator->destroy(enumerator); + + return enumerator_create_nested(data->list->create_enumerator(data->list), + create_nested, data, nested_cleanup); +} + +/** + * Merge a pool configuration with existing ones + */ +static bool merge_pool(private_vici_attribute_t *this, pool_t *new) +{ + mem_pool_t *tmp; + host_t *base; + pool_t *old; + const char *name; + u_int size; + + name = new->vips->get_name(new->vips); + base = new->vips->get_base(new->vips); + size = new->vips->get_size(new->vips); + + old = this->pools->remove(this->pools, name); + if (!old) + { + this->pools->put(this->pools, name, new); + DBG1(DBG_CFG, "added vici pool %s: %H, %u entries", name, base, size); + return TRUE; + } + + if (base->ip_equals(base, old->vips->get_base(old->vips)) && + size == old->vips->get_size(old->vips)) + { + /* no changes in pool, so keep existing, but use new attributes */ + DBG1(DBG_CFG, "updated vici pool %s: %H, %u entries", name, base, size); + tmp = new->vips; + new->vips = old->vips; + old->vips = tmp; + this->pools->put(this->pools, new->vips->get_name(new->vips), new); + pool_destroy(old); + return TRUE; + } + if (old->vips->get_online(old->vips) == 0) + { + /* can replace old pool, no online leases */ + DBG1(DBG_CFG, "replaced vici pool %s: %H, %u entries", name, base, size); + this->pools->put(this->pools, name, new); + pool_destroy(old); + return TRUE; + } + /* have online leases, unable to replace, TODO: migrate leases? */ + DBG1(DBG_CFG, "vici pool %s has %u online leases, unable to replace", + name, old->vips->get_online(old->vips)); + this->pools->put(this->pools, old->vips->get_name(old->vips), old); + return FALSE; +} + +/** + * Create a (error) reply message + */ +static vici_message_t* create_reply(char *fmt, ...) +{ + vici_builder_t *builder; + va_list args; + + builder = vici_builder_create(); + builder->add_kv(builder, "success", fmt ? "no" : "yes"); + if (fmt) + { + va_start(args, fmt); + builder->vadd_kv(builder, "errmsg", fmt, args); + va_end(args); + } + return builder->finalize(builder); +} + +/** + * Parse callback data, passed to each callback + */ +typedef struct { + private_vici_attribute_t *this; + vici_message_t *reply; +} request_data_t; + +/** + * Data associated to a pool load + */ +typedef struct { + request_data_t *request; + char *name; + pool_t *pool; +} load_data_t; + +CALLBACK(pool_li, bool, + load_data_t *data, vici_message_t *message, char *name, chunk_t value) +{ + struct { + char *name; + configuration_attribute_type_t v4; + configuration_attribute_type_t v6; + } keys[] = { + {"address", INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS }, + {"dns", INTERNAL_IP4_DNS, INTERNAL_IP6_DNS }, + {"nbns", INTERNAL_IP4_NBNS, INTERNAL_IP6_NBNS }, + {"dhcp", INTERNAL_IP4_DHCP, INTERNAL_IP6_DHCP }, + {"netmask", INTERNAL_IP4_NETMASK, INTERNAL_IP6_NETMASK }, + {"server", INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER }, + {"subnet", INTERNAL_IP4_SUBNET, INTERNAL_IP6_SUBNET }, + {"split_include", UNITY_SPLIT_INCLUDE, UNITY_SPLIT_INCLUDE }, + {"split_exclude", UNITY_LOCAL_LAN, UNITY_LOCAL_LAN }, + }; + char buf[256]; + int i, index = -1, mask = -1, type = 0; + chunk_t encoding; + attribute_t *attr; + host_t *host = NULL; + + for (i = 0; i < countof(keys); i++) + { + if (streq(name, keys[i].name)) + { + index = i; + break; + } + } + if (index == -1) + { + type = atoi(name); + if (!type) + { + data->request->reply = create_reply("invalid attribute: %s", name); + return FALSE; + } + } + + if (vici_stringify(value, buf, sizeof(buf))) + { + if (strchr(buf, '/')) + { + host = host_create_from_subnet(buf, &mask); + } + else + { + host = host_create_from_string(buf, 0); + } + } + if (host) + { + if (index != -1) + { + switch (host->get_family(host)) + { + case AF_INET: + type = keys[index].v4; + break; + case AF_INET6: + default: + type = keys[index].v6; + break; + } + } + if (mask == -1) + { + encoding = chunk_clone(host->get_address(host)); + } + else + { + if (host->get_family(host) == AF_INET) + { /* IPv4 attributes contain a subnet mask */ + u_int32_t netmask = 0; + + if (mask) + { /* shifting u_int32_t by 32 or more is undefined */ + mask = 32 - mask; + netmask = htonl((0xFFFFFFFF >> mask) << mask); + } + encoding = chunk_cat("cc", host->get_address(host), + chunk_from_thing(netmask)); + } + else + { /* IPv6 addresses the prefix only */ + encoding = chunk_cat("cc", host->get_address(host), + chunk_from_chars(mask)); + } + } + host->destroy(host); + } + else + { + if (index != -1) + { + data->request->reply = create_reply("invalid attribute value " + "for %s", name); + return FALSE; + } + /* use raw binary data for numbered attributes */ + encoding = chunk_clone(value); + } + INIT(attr, + .type = type, + .value = encoding, + ); + array_insert_create(&data->pool->attrs, ARRAY_TAIL, attr); + return TRUE; +} + +CALLBACK(pool_kv, bool, + load_data_t *data, vici_message_t *message, char *name, chunk_t value) +{ + if (streq(name, "addrs")) + { + char buf[128]; + host_t *base; + int bits; + + if (data->pool->vips) + { + data->request->reply = create_reply("multiple addrs defined"); + return FALSE; + } + if (!vici_stringify(value, buf, sizeof(buf))) + { + data->request->reply = create_reply("invalid addrs value"); + return FALSE; + } + base = host_create_from_subnet(buf, &bits); + if (!base) + { + data->request->reply = create_reply("invalid addrs value: %s", buf); + return FALSE; + } + data->pool->vips = mem_pool_create(data->name, base, bits); + base->destroy(base); + return TRUE; + } + data->request->reply = create_reply("invalid attribute: %s", name); + return FALSE; +} + +CALLBACK(pool_sn, bool, + request_data_t *request, vici_message_t *message, + vici_parse_context_t *ctx, char *name) +{ + load_data_t data = { + .request = request, + .name = name, + }; + bool merged; + + INIT(data.pool); + + if (!message->parse(message, ctx, NULL, pool_kv, pool_li, &data)) + { + pool_destroy(data.pool); + return FALSE; + } + + if (!data.pool->vips) + { + request->reply = create_reply("missing addrs for pool '%s'", name); + pool_destroy(data.pool); + return FALSE; + } + + request->this->lock->write_lock(request->this->lock); + merged = merge_pool(request->this, data.pool); + request->this->lock->unlock(request->this->lock); + + if (!merged) + { + request->reply = create_reply("vici pool %s has online leases, " + "unable to replace", name); + pool_destroy(data.pool); + } + return merged; +} + +CALLBACK(load_pool, vici_message_t*, + private_vici_attribute_t *this, char *name, u_int id, + vici_message_t *message) +{ + request_data_t request = { + .this = this, + }; + + if (!message->parse(message, NULL, pool_sn, NULL, NULL, &request)) + { + if (request.reply) + { + return request.reply; + } + return create_reply("parsing request failed"); + } + return create_reply(NULL); +} + +CALLBACK(unload_pool, vici_message_t*, + private_vici_attribute_t *this, char *name, u_int id, + vici_message_t *message) +{ + vici_message_t *reply; + u_int online; + pool_t *pool; + + name = message->get_str(message, NULL, "name"); + if (!name) + { + return create_reply("missing pool name to unload"); + } + + this->lock->write_lock(this->lock); + + pool = this->pools->remove(this->pools, name); + if (pool) + { + online = pool->vips->get_online(pool->vips); + if (online) + { + DBG1(DBG_CFG, "vici pool %s has %u online leases, unable to unload", + name, online); + reply = create_reply("%s has online leases, unable to unload", name); + this->pools->put(this->pools, pool->vips->get_name(pool->vips), pool); + } + else + { + DBG1(DBG_CFG, "unloaded vici pool %s", name); + reply = create_reply(NULL); + pool_destroy(pool); + } + } + else + { + reply = create_reply("%s not found", name); + } + + this->lock->unlock(this->lock); + + return reply; +} + +CALLBACK(get_pools, vici_message_t*, + private_vici_attribute_t *this, char *name, u_int id, + vici_message_t *message) +{ + vici_builder_t *builder; + enumerator_t *enumerator; + mem_pool_t *vips; + pool_t *pool; + + builder = vici_builder_create(); + + this->lock->read_lock(this->lock); + enumerator = this->pools->create_enumerator(this->pools); + while (enumerator->enumerate(enumerator, &name, &pool)) + { + vips = pool->vips; + + builder->begin_section(builder, name); + + builder->add_kv(builder, "base", "%H", vips->get_base(vips)); + builder->add_kv(builder, "size", "%u", vips->get_size(vips)); + builder->add_kv(builder, "online", "%u", vips->get_online(vips)); + builder->add_kv(builder, "offline", "%u", vips->get_offline(vips)); + + builder->end_section(builder); + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return builder->finalize(builder); +} + +static void manage_command(private_vici_attribute_t *this, + char *name, vici_command_cb_t cb, bool reg) +{ + this->dispatcher->manage_command(this->dispatcher, name, + reg ? cb : NULL, this); +} + +/** + * (Un-)register dispatcher functions + */ +static void manage_commands(private_vici_attribute_t *this, bool reg) +{ + manage_command(this, "load-pool", load_pool, reg); + manage_command(this, "unload-pool", unload_pool, reg); + manage_command(this, "get-pools", get_pools, reg); +} + +METHOD(vici_attribute_t, destroy, void, + private_vici_attribute_t *this) +{ + enumerator_t *enumerator; + pool_t *pool; + + manage_commands(this, FALSE); + + enumerator = this->pools->create_enumerator(this->pools); + while (enumerator->enumerate(enumerator, NULL, &pool)) + { + pool_destroy(pool); + } + enumerator->destroy(enumerator); + this->pools->destroy(this->pools); + this->lock->destroy(this->lock); + free(this); +} + +/* + * see header file + */ +vici_attribute_t *vici_attribute_create(vici_dispatcher_t *dispatcher) +{ + private_vici_attribute_t *this; + + INIT(this, + .public = { + .provider = { + .acquire_address = _acquire_address, + .release_address = _release_address, + .create_attribute_enumerator = _create_attribute_enumerator, + }, + .destroy = _destroy, + }, + .dispatcher = dispatcher, + .pools = hashtable_create(hashtable_hash_str, hashtable_equals_str, 4), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + manage_commands(this, TRUE); + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_attribute.h b/src/libcharon/plugins/vici/vici_attribute.h new file mode 100644 index 000000000..652a96d39 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_attribute.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_attribute vici_attribute + * @{ @ingroup vici + */ + +#ifndef VICI_ATTRIBUTE_H_ +#define VICI_ATTRIBUTE_H_ + +#include "vici_dispatcher.h" + +#include <attributes/attribute_provider.h> + +typedef struct vici_attribute_t vici_attribute_t; + +/** + * IKE configuration attribute backend for vici. + */ +struct vici_attribute_t { + + /** + * Implements attribute provider interface + */ + attribute_provider_t provider; + + /** + * Destroy a vici_attribute_t. + */ + void (*destroy)(vici_attribute_t *this); +}; + +/** + * Create a vici_attribute instance. + * + * @param dispatcher vici dispatcher context + * @return vici attribute handler + */ +vici_attribute_t *vici_attribute_create(vici_dispatcher_t *dispatcher); + +#endif /** VICI_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_builder.c b/src/libcharon/plugins/vici/vici_builder.c new file mode 100644 index 000000000..561632049 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_builder.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_builder.h" + +#include <bio/bio_writer.h> + +typedef struct private_vici_builder_t private_vici_builder_t; + +/** + * Private data of an vici_builder_t object. + */ +struct private_vici_builder_t { + + /** + * Public vici_builder_t interface. + */ + vici_builder_t public; + + /** + * Writer for elements + */ + bio_writer_t *writer; + + /** + * Errors encountered + */ + u_int error; + + /** + * Section nesting level + */ + u_int section; + + /** + * In list element? + */ + bool list; +}; + +METHOD(vici_builder_t, add, void, + private_vici_builder_t *this, vici_type_t type, ...) +{ + va_list args; + char *name = NULL; + chunk_t value = chunk_empty; + + va_start(args, type); + switch (type) + { + case VICI_SECTION_END: + case VICI_LIST_END: + case VICI_END: + break; + case VICI_LIST_START: + case VICI_SECTION_START: + name = va_arg(args, char*); + break; + case VICI_KEY_VALUE: + name = va_arg(args, char*); + value = va_arg(args, chunk_t); + break; + case VICI_LIST_ITEM: + value = va_arg(args, chunk_t); + break; + default: + va_end(args); + this->error++; + return; + } + va_end(args); + + if (value.len > 0xffff) + { + this->error++; + return; + } + if (!vici_verify_type(type, this->section, this->list)) + { + this->error++; + return; + } + if (type != VICI_END) + { + this->writer->write_uint8(this->writer, type); + } + switch (type) + { + case VICI_SECTION_START: + this->writer->write_data8(this->writer, chunk_from_str(name)); + this->section++; + break; + case VICI_SECTION_END: + this->section--; + break; + case VICI_KEY_VALUE: + this->writer->write_data8(this->writer, chunk_from_str(name)); + this->writer->write_data16(this->writer, value); + break; + case VICI_LIST_START: + this->writer->write_data8(this->writer, chunk_from_str(name)); + this->list = TRUE; + break; + case VICI_LIST_ITEM: + this->writer->write_data16(this->writer, value); + break; + case VICI_LIST_END: + this->list = FALSE; + break; + default: + this->error++; + break; + } +} + +METHOD(vici_builder_t, vadd_kv, void, + private_vici_builder_t *this, char *key, char *fmt, va_list args) +{ + char buf[2048]; + ssize_t len; + + len = vsnprintf(buf, sizeof(buf), fmt, args); + if (len < 0 || len >= sizeof(buf)) + { + DBG1(DBG_ENC, "vici builder format buffer exceeds limit"); + this->error++; + } + else + { + add(this, VICI_KEY_VALUE, key, chunk_create(buf, len)); + } +} + +METHOD(vici_builder_t, add_kv, void, + private_vici_builder_t *this, char *key, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vadd_kv(this, key, fmt, args); + va_end(args); +} + + +METHOD(vici_builder_t, vadd_li, void, + private_vici_builder_t *this, char *fmt, va_list args) +{ + char buf[2048]; + ssize_t len; + + len = vsnprintf(buf, sizeof(buf), fmt, args); + if (len < 0 || len >= sizeof(buf)) + { + DBG1(DBG_ENC, "vici builder format buffer exceeds limit"); + this->error++; + } + else + { + add(this, VICI_LIST_ITEM, chunk_create(buf, len)); + } +} + +METHOD(vici_builder_t, add_li, void, + private_vici_builder_t *this, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vadd_li(this, fmt, args); + va_end(args); +} + +METHOD(vici_builder_t, begin_section, void, + private_vici_builder_t *this, char *name) +{ + add(this, VICI_SECTION_START, name); +} + +METHOD(vici_builder_t, end_section, void, + private_vici_builder_t *this) +{ + add(this, VICI_SECTION_END); +} + +METHOD(vici_builder_t, begin_list, void, + private_vici_builder_t *this, char *name) +{ + add(this, VICI_LIST_START, name); +} + +METHOD(vici_builder_t, end_list, void, + private_vici_builder_t *this) +{ + add(this, VICI_LIST_END); +} + +METHOD(vici_builder_t, finalize, vici_message_t*, + private_vici_builder_t *this) +{ + vici_message_t *product; + + if (this->error || this->section || this->list) + { + DBG1(DBG_ENC, "vici builder error: %u errors (section: %u, list %u)", + this->error, this->section, this->list); + this->writer->destroy(this->writer); + free(this); + return NULL; + } + product = vici_message_create_from_data( + this->writer->extract_buf(this->writer), TRUE); + this->writer->destroy(this->writer); + free(this); + return product; +} + +/** + * See header + */ +vici_builder_t *vici_builder_create() +{ + private_vici_builder_t *this; + + INIT(this, + .public = { + .add = _add, + .add_kv = _add_kv, + .vadd_kv = _vadd_kv, + .add_li = _add_li, + .vadd_li = _vadd_li, + .begin_section = _begin_section, + .end_section = _end_section, + .begin_list = _begin_list, + .end_list = _end_list, + .finalize = _finalize, + }, + .writer = bio_writer_create(0), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_builder.h b/src/libcharon/plugins/vici/vici_builder.h new file mode 100644 index 000000000..5a5cc8a03 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_builder.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_builder vici_builder + * @{ @ingroup vici + */ + +#ifndef VICI_BUILDER_H_ +#define VICI_BUILDER_H_ + +#include "vici_message.h" + +typedef struct vici_builder_t vici_builder_t; + +/** + * Build helper for vici message + */ +struct vici_builder_t { + + /** + * Append a generic message element to message. + * + * The additional arguments are type specific, it may be nothing, a string, + * a chunk value or both. + * + * @param type element type to add + * @param ... additional type specific arguments + */ + void (*add)(vici_builder_t *this, vici_type_t type, ...); + + /** + * Append a key/value element using a format string. + * + * Instead of passing the type specific value as a chunk, this method + * takes a printf() style format string followed by its arguments. The + * key name for a key/value type is still a fixed string. + * + * @param key key name of the key/value to add + * @param fmt value format string + * @param ... arguments to value format string + */ + void (*add_kv)(vici_builder_t *this, char *key, char *fmt, ...); + + /** + * Append a message element using a format string and va_list. + * + * Instead of passing the type specific value as a chunk, this method + * takes a printf() style format string followed by its arguments. The + * key name for a key/value type is still a fixed string. + * + * @param key key name of the key/value to add + * @param fmt value format string + * @param args arguments to value format string + */ + void (*vadd_kv)(vici_builder_t *this, char *key, char *fmt, va_list args); + + /** + * Append a list item element using a format string. + * + * Instead of passing the type specific value as a chunk, this method + * takes a printf() style format string followed by its arguments. + * + * @param fmt value format string + * @param ... arguments to value format string + */ + void (*add_li)(vici_builder_t *this, char *fmt, ...); + + /** + * Append a list item element using a format string and va_list. + * + * Instead of passing the type specific value as a chunk, this method + * takes a printf() style format string followed by its arguments. + * + * @param fmt value format string + * @param args arguments to value format string + */ + void (*vadd_li)(vici_builder_t *this, char *fmt, va_list args); + + /** + * Begin a new section. + * + * @param name name of section to begin + */ + void (*begin_section)(vici_builder_t *this, char *name); + + /** + * End the currently open section. + */ + void (*end_section)(vici_builder_t *this); + + /** + * Begin a new list. + * + * @param name name of list to begin + */ + void (*begin_list)(vici_builder_t *this, char *name); + + /** + * End the currently open list. + */ + void (*end_list)(vici_builder_t *this); + + /** + * Finalize a vici message with all added elements, destroy builder. + * + * @return vici message, NULL on error + */ + vici_message_t* (*finalize)(vici_builder_t *this); +}; + +/** + * Create a vici_builder instance. + */ +vici_builder_t *vici_builder_create(); + +#endif /** VICI_BUILDER_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c new file mode 100644 index 000000000..113d48084 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_config.c @@ -0,0 +1,2006 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE + +#include "vici_config.h" +#include "vici_builder.h" + +#include <daemon.h> +#include <threading/rwlock.h> +#include <collections/array.h> +#include <collections/linked_list.h> + +#include <stdio.h> + +/** + * Magic value for an undefined lifetime + */ +#define LFT_UNDEFINED (~(u_int64_t)0) + +/** + * Default IKE rekey time + */ +#define LFT_DEFAULT_IKE_REKEY (4 * 60 * 60) + +/** + * Default CHILD rekey time + */ +#define LFT_DEFAULT_CHILD_REKEY (1 * 60 * 60) + +/** + * Undefined replay window + */ +#define REPLAY_UNDEFINED (~(u_int32_t)0) + +typedef struct private_vici_config_t private_vici_config_t; + +/** + * Private data of an vici_config_t object. + */ +struct private_vici_config_t { + + /** + * Public vici_config_t interface. + */ + vici_config_t public; + + /** + * Dispatcher + */ + vici_dispatcher_t *dispatcher; + + /** + * List of loaded connections, as peer_cfg_t + */ + linked_list_t *conns; + + /** + * Lock for conns list + */ + rwlock_t *lock; +}; + +METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, + private_vici_config_t *this, identification_t *me, identification_t *other) +{ + this->lock->read_lock(this->lock); + return enumerator_create_cleaner(this->conns->create_enumerator(this->conns), + (void*)this->lock->unlock, this->lock); +} + +/** + * Enumerator filter function for ike configs + */ +static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out) +{ + *out = (*in)->get_ike_cfg(*in); + return TRUE; +} + +METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*, + private_vici_config_t *this, host_t *me, host_t *other) +{ + this->lock->read_lock(this->lock); + return enumerator_create_filter(this->conns->create_enumerator(this->conns), + (void*)ike_filter, this->lock, + (void*)this->lock->unlock); +} + +METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, + private_vici_config_t *this, char *name) +{ + peer_cfg_t *current, *found = NULL; + enumerator_t *enumerator; + + this->lock->read_lock(this->lock); + enumerator = this->conns->create_enumerator(this->conns); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(current->get_name(current), name)) + { + found = current; + found->get_ref(found); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return found; +} + +/** + * Create a (error) reply message + */ +static vici_message_t* create_reply(char *fmt, ...) +{ + vici_builder_t *builder; + va_list args; + + builder = vici_builder_create(); + builder->add_kv(builder, "success", fmt ? "no" : "yes"); + if (fmt) + { + va_start(args, fmt); + builder->vadd_kv(builder, "errmsg", fmt, args); + va_end(args); + } + return builder->finalize(builder); +} + +/** + * A rule to parse a key/value or list item + */ +typedef struct { + /** name of the key/value or list */ + char *name; + /** function to parse value */ + bool (*parse)(void *out, chunk_t value); + /** result, passed to parse() */ + void *out; +} parse_rule_t; + +/** + * Parse key/values using a rule-set + */ +static bool parse_rules(parse_rule_t *rules, int count, char *name, + chunk_t value, vici_message_t **reply) +{ + int i; + + for (i = 0; i < count; i++) + { + if (streq(name, rules[i].name)) + { + if (rules[i].parse(rules[i].out, value)) + { + return TRUE; + } + *reply = create_reply("invalid value for: %s, config discarded", + name); + return FALSE; + } + } + *reply = create_reply("unknown option: %s, config discarded", name); + return FALSE; +} + +/** + * Parse callback data, passed to each callback + */ +typedef struct { + private_vici_config_t *this; + vici_message_t *reply; +} request_data_t; + +/** + * Data associated to a peer config + */ +typedef struct { + request_data_t *request; + u_int32_t version; + bool aggressive; + bool encap; + bool mobike; + bool send_certreq; + bool pull; + cert_policy_t send_cert; + u_int64_t dpd_delay; + u_int64_t dpd_timeout; + fragmentation_t fragmentation; + unique_policy_t unique; + u_int32_t keyingtries; + u_int32_t local_port; + u_int32_t remote_port; + char *local_addrs; + char *remote_addrs; + linked_list_t *local; + linked_list_t *remote; + linked_list_t *proposals; + linked_list_t *children; + linked_list_t *vips; + char *pools; + u_int64_t reauth_time; + u_int64_t rekey_time; + u_int64_t over_time; + u_int64_t rand_time; +} peer_data_t; + +/** + * Log relevant auth config data + */ +static void log_auth(auth_cfg_t *auth) +{ + enumerator_t *enumerator; + auth_rule_t rule; + union { + uintptr_t u; + identification_t *id; + char *str; + } v; + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &rule, &v)) + { + switch (rule) + { + case AUTH_RULE_AUTH_CLASS: + DBG2(DBG_CFG, " class = %N", auth_class_names, v.u); + break; + case AUTH_RULE_EAP_TYPE: + DBG2(DBG_CFG, " eap-type = %N", eap_type_names, v.u); + break; + case AUTH_RULE_EAP_VENDOR: + DBG2(DBG_CFG, " eap-vendor = %u", v.u); + break; + case AUTH_RULE_XAUTH_BACKEND: + DBG2(DBG_CFG, " xauth = %s", v.str); + break; + case AUTH_RULE_CRL_VALIDATION: + DBG2(DBG_CFG, " revocation = %N", cert_validation_names, v.u); + break; + case AUTH_RULE_IDENTITY: + DBG2(DBG_CFG, " id = %Y", v.id); + break; + case AUTH_RULE_AAA_IDENTITY: + DBG2(DBG_CFG, " aaa_id = %Y", v.id); + break; + case AUTH_RULE_EAP_IDENTITY: + DBG2(DBG_CFG, " eap_id = %Y", v.id); + break; + case AUTH_RULE_XAUTH_IDENTITY: + DBG2(DBG_CFG, " xauth_id = %Y", v.id); + break; + case AUTH_RULE_GROUP: + DBG2(DBG_CFG, " group = %Y", v.id); + break; + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Log parsed peer data + */ +static void log_peer_data(peer_data_t *data) +{ + enumerator_t *enumerator; + auth_cfg_t *auth; + host_t *host; + + DBG2(DBG_CFG, " version = %u", data->version); + DBG2(DBG_CFG, " local_addrs = %s", data->local_addrs); + DBG2(DBG_CFG, " remote_addrs = %s", data->remote_addrs); + DBG2(DBG_CFG, " local_port = %u", data->local_port); + DBG2(DBG_CFG, " remote_port = %u", data->remote_port); + DBG2(DBG_CFG, " send_certreq = %u", data->send_certreq); + DBG2(DBG_CFG, " send_cert = %N", cert_policy_names, data->send_cert); + DBG2(DBG_CFG, " mobike = %u", data->mobike); + DBG2(DBG_CFG, " aggressive = %u", data->aggressive); + DBG2(DBG_CFG, " encap = %u", data->encap); + DBG2(DBG_CFG, " dpd_delay = %llu", data->dpd_delay); + DBG2(DBG_CFG, " dpd_timeout = %llu", data->dpd_timeout); + DBG2(DBG_CFG, " fragmentation = %u", data->fragmentation); + DBG2(DBG_CFG, " unique = %N", unique_policy_names, data->unique); + DBG2(DBG_CFG, " keyingtries = %u", data->keyingtries); + DBG2(DBG_CFG, " reauth_time = %llu", data->reauth_time); + DBG2(DBG_CFG, " rekey_time = %llu", data->rekey_time); + DBG2(DBG_CFG, " over_time = %llu", data->over_time); + DBG2(DBG_CFG, " rand_time = %llu", data->rand_time); + DBG2(DBG_CFG, " proposals = %#P", data->proposals); + + if (data->vips->get_count(data->vips)) + { + DBG2(DBG_CFG, " vips:"); + } + enumerator = data->vips->create_enumerator(data->vips); + while (enumerator->enumerate(enumerator, &host)) + { + DBG2(DBG_CFG, " %H", host); + } + enumerator->destroy(enumerator); + + enumerator = data->local->create_enumerator(data->local); + while (enumerator->enumerate(enumerator, &auth)) + { + DBG2(DBG_CFG, " local:"); + log_auth(auth); + } + enumerator->destroy(enumerator); + + enumerator = data->remote->create_enumerator(data->remote); + while (enumerator->enumerate(enumerator, &auth)) + { + DBG2(DBG_CFG, " remote:"); + log_auth(auth); + } + enumerator->destroy(enumerator); +} + +/** + * Clean up peer config data + */ +static void free_peer_data(peer_data_t *data) +{ + data->local->destroy_offset(data->local, + offsetof(auth_cfg_t, destroy)); + data->remote->destroy_offset(data->remote, + offsetof(auth_cfg_t, destroy)); + data->children->destroy_offset(data->children, + offsetof(child_cfg_t, destroy)); + data->proposals->destroy_offset(data->proposals, + offsetof(proposal_t, destroy)); + data->vips->destroy_offset(data->vips, offsetof(host_t, destroy)); + free(data->pools); + free(data->local_addrs); + free(data->remote_addrs); +} + +/** + * CHILD config data + */ +typedef struct { + request_data_t *request; + lifetime_cfg_t lft; + char* updown; + bool hostaccess; + bool ipcomp; + bool route; + ipsec_mode_t mode; + u_int32_t replay_window; + action_t dpd_action; + action_t start_action; + action_t close_action; + u_int32_t reqid; + u_int32_t tfc; + mark_t mark_in; + mark_t mark_out; + u_int64_t inactivity; + linked_list_t *proposals; + linked_list_t *local_ts; + linked_list_t *remote_ts; +} child_data_t; + +/** + * Log parsed CHILD config data + */ +static void log_child_data(child_data_t *data, char *name) +{ + DBG2(DBG_CFG, " child %s:", name); + DBG2(DBG_CFG, " rekey_time = %llu", data->lft.time.rekey); + DBG2(DBG_CFG, " life_time = %llu", data->lft.time.life); + DBG2(DBG_CFG, " rand_time = %llu", data->lft.time.jitter); + DBG2(DBG_CFG, " rekey_bytes = %llu", data->lft.bytes.rekey); + DBG2(DBG_CFG, " life_bytes = %llu", data->lft.bytes.life); + DBG2(DBG_CFG, " rand_bytes = %llu", data->lft.bytes.jitter); + DBG2(DBG_CFG, " rekey_packets = %llu", data->lft.packets.rekey); + DBG2(DBG_CFG, " life_packets = %llu", data->lft.packets.life); + DBG2(DBG_CFG, " rand_packets = %llu", data->lft.packets.jitter); + DBG2(DBG_CFG, " updown = %s", data->updown); + DBG2(DBG_CFG, " hostaccess = %u", data->hostaccess); + DBG2(DBG_CFG, " ipcomp = %u", data->ipcomp); + DBG2(DBG_CFG, " mode = %N", ipsec_mode_names, data->mode); + if (data->replay_window != REPLAY_UNDEFINED) + { + DBG2(DBG_CFG, " replay_window = %u", data->replay_window); + } + DBG2(DBG_CFG, " dpd_action = %N", action_names, data->dpd_action); + DBG2(DBG_CFG, " start_action = %N", action_names, data->start_action); + DBG2(DBG_CFG, " close_action = %N", action_names, data->close_action); + DBG2(DBG_CFG, " reqid = %u", data->reqid); + DBG2(DBG_CFG, " tfc = %d", data->tfc); + DBG2(DBG_CFG, " mark_in = %u/%u", + data->mark_in.value, data->mark_in.mask); + DBG2(DBG_CFG, " mark_out = %u/%u", + data->mark_out.value, data->mark_out.mask); + DBG2(DBG_CFG, " inactivity = %llu", data->inactivity); + DBG2(DBG_CFG, " proposals = %#P", data->proposals); + DBG2(DBG_CFG, " local_ts = %#R", data->local_ts); + DBG2(DBG_CFG, " remote_ts = %#R", data->remote_ts); +} + +/** + * Clean up CHILD config data + */ +static void free_child_data(child_data_t *data) +{ + data->proposals->destroy_offset(data->proposals, + offsetof(proposal_t, destroy)); + data->local_ts->destroy_offset(data->local_ts, + offsetof(traffic_selector_t, destroy)); + data->remote_ts->destroy_offset(data->remote_ts, + offsetof(traffic_selector_t, destroy)); + free(data->updown); +} + +/** + * Auth config data + */ +typedef struct { + request_data_t *request; + auth_cfg_t *cfg; +} auth_data_t; + +/** + * Common proposal parsing + */ +static bool parse_proposal(linked_list_t *list, protocol_id_t proto, chunk_t v) +{ + char buf[128]; + proposal_t *proposal; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + if (strcaseeq("default", buf)) + { + proposal = proposal_create_default(proto); + if (proposal) + { + list->insert_last(list, proposal); + } + proposal = proposal_create_default_aead(proto); + if (proposal) + { + list->insert_last(list, proposal); + } + return TRUE; + } + proposal = proposal_create_from_string(proto, buf); + if (proposal) + { + list->insert_last(list, proposal); + return TRUE; + } + return FALSE; +} + +/** + * Parse IKE proposal + */ +CALLBACK(parse_ike_proposal, bool, + linked_list_t *out, chunk_t v) +{ + return parse_proposal(out, PROTO_IKE, v); +} + +/** + * Parse ESP proposal + */ +CALLBACK(parse_esp_proposal, bool, + linked_list_t *out, chunk_t v) +{ + return parse_proposal(out, PROTO_ESP, v); +} + +/** + * Parse AH proposal + */ +CALLBACK(parse_ah_proposal, bool, + linked_list_t *out, chunk_t v) +{ + return parse_proposal(out, PROTO_AH, v); +} + +/** + * Parse a traffic selector + */ +CALLBACK(parse_ts, bool, + linked_list_t *out, chunk_t v) +{ + char buf[128], *protoport, *sep, *port = "", *end; + traffic_selector_t *ts; + struct protoent *protoent; + struct servent *svc; + long int p; + u_int16_t from = 0, to = 0xffff; + u_int8_t proto = 0; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + + protoport = strchr(buf, '['); + if (protoport) + { + *(protoport++) = '\0'; + + sep = strrchr(protoport, ']'); + if (!sep) + { + return FALSE; + } + *sep = '\0'; + + sep = strchr(protoport, '/'); + if (sep) + { /* protocol/port */ + *sep = '\0'; + port = sep + 1; + } + + if (streq(protoport, "any")) + { + proto = 0; + } + else + { + protoent = getprotobyname(protoport); + if (protoent) + { + proto = protoent->p_proto; + } + else + { + p = strtol(protoport, &end, 0); + if ((*protoport && *end) || p < 0 || p > 0xff) + { + return FALSE; + } + proto = (u_int8_t)p; + } + } + if (streq(port, "opaque")) + { + from = 0xffff; + to = 0; + } + else if (*port && !streq(port, "any")) + { + svc = getservbyname(port, NULL); + if (svc) + { + from = to = ntohs(svc->s_port); + } + else + { + p = strtol(port, &end, 0); + if (p < 0 || p > 0xffff) + { + return FALSE; + } + from = p; + if (*end == '-') + { + port = end + 1; + p = strtol(port, &end, 0); + if (p < 0 || p > 0xffff) + { + return FALSE; + } + } + to = p; + if (*end) + { + return FALSE; + } + } + } + } + if (streq(buf, "dynamic")) + { + ts = traffic_selector_create_dynamic(proto, from, to); + } + else + { + ts = traffic_selector_create_from_cidr(buf, proto, from, to); + } + if (!ts) + { + return FALSE; + } + out->insert_last(out, ts); + return TRUE; +} + +/** + * Parse a string + */ +CALLBACK(parse_string, bool, + char **out, chunk_t v) +{ + if (!chunk_printable(v, NULL, ' ')) + { + return FALSE; + } + free(*out); + *out = NULL; + if (asprintf(out, "%.*s", (int)v.len, v.ptr) == -1) + { + return FALSE; + } + return TRUE; +} + +/** + * Map a string to an integer + */ +typedef struct { + char *str; + int d; +} enum_map_t; + +/** + * Parse a string to an integer mapping + */ +static bool parse_map(enum_map_t *map, int count, int *out, chunk_t v) +{ + char buf[128]; + int i; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + for (i = 0; i < count; i++) + { + if (strcaseeq(map[i].str, buf)) + { + *out = map[i].d; + return TRUE; + } + } + return FALSE; +} + +/** + * Parse a boolean + */ +CALLBACK(parse_bool, bool, + bool *out, chunk_t v) +{ + enum_map_t map[] = { + { "yes", TRUE }, + { "true", TRUE }, + { "enabled", TRUE }, + { "1", TRUE }, + { "no", FALSE }, + { "false", FALSE }, + { "disabled", FALSE }, + { "0", FALSE }, + }; + int d; + + if (parse_map(map, countof(map), &d, v)) + { + *out = d; + return TRUE; + } + return FALSE; +} + +/** + * Parse a ipsec_mode_t + */ +CALLBACK(parse_mode, bool, + ipsec_mode_t *out, chunk_t v) +{ + enum_map_t map[] = { + { "tunnel", MODE_TUNNEL }, + { "transport", MODE_TRANSPORT }, + { "beet", MODE_BEET }, + { "drop", MODE_DROP }, + { "pass", MODE_PASS }, + }; + int d; + + if (parse_map(map, countof(map), &d, v)) + { + *out = d; + return TRUE; + } + return FALSE; +} + +/** + * Parse an action_t + */ +CALLBACK(parse_action, bool, + action_t *out, chunk_t v) +{ + enum_map_t map[] = { + { "start", ACTION_RESTART }, + { "restart", ACTION_RESTART }, + { "route", ACTION_ROUTE }, + { "trap", ACTION_ROUTE }, + { "none", ACTION_NONE }, + { "clear", ACTION_NONE }, + }; + int d; + + if (parse_map(map, countof(map), &d, v)) + { + *out = d; + return TRUE; + } + return FALSE; +} + +/** + * Parse a u_int32_t + */ +CALLBACK(parse_uint32, bool, + u_int32_t *out, chunk_t v) +{ + char buf[16], *end; + u_long l; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + l = strtoul(buf, &end, 0); + if (*end == 0) + { + *out = l; + return TRUE; + } + return FALSE; +} + +/** + * Parse a u_int64_t + */ +CALLBACK(parse_uint64, bool, + u_int64_t *out, chunk_t v) +{ + char buf[16], *end; + unsigned long long l; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + l = strtoull(buf, &end, 0); + if (*end == 0) + { + *out = l; + return TRUE; + } + return FALSE; +} + +/** + * Parse a relative time + */ +CALLBACK(parse_time, bool, + u_int64_t *out, chunk_t v) +{ + char buf[16], *end; + u_long l; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + + l = strtoul(buf, &end, 0); + while (*end == ' ') + { + end++; + } + switch (*end) + { + case 'd': + case 'D': + l *= 24; + /* fall */ + case 'h': + case 'H': + l *= 60; + /* fall */ + case 'm': + case 'M': + l *= 60; + /* fall */ + case 's': + case 'S': + end++; + break; + case '\0': + break; + default: + return FALSE; + } + if (*end) + { + return FALSE; + } + *out = l; + return TRUE; +} + +/** + * Parse byte volume + */ +CALLBACK(parse_bytes, bool, + u_int64_t *out, chunk_t v) +{ + char buf[16], *end; + unsigned long long l; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + + l = strtoull(buf, &end, 0); + while (*end == ' ') + { + end++; + } + switch (*end) + { + case 'g': + case 'G': + l *= 1024; + /* fall */ + case 'm': + case 'M': + l *= 1024; + /* fall */ + case 'k': + case 'K': + l *= 1024; + end++; + break; + case '\0': + break; + default: + return FALSE; + } + if (*end) + { + return FALSE; + } + *out = l; + return TRUE; +} + +/** + * Parse a mark_t + */ +CALLBACK(parse_mark, bool, + mark_t *out, chunk_t v) +{ + char buf[32]; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + return mark_from_string(buf, out); +} + +/** + * Parse TFC padding option + */ +CALLBACK(parse_tfc, bool, + u_int32_t *out, chunk_t v) +{ + if (chunk_equals(v, chunk_from_str("mtu"))) + { + *out = -1; + return TRUE; + } + return parse_uint32(out, v); +} + +/** + * Parse authentication config + */ +CALLBACK(parse_auth, bool, + auth_cfg_t *cfg, chunk_t v) +{ + char buf[64], *pos; + eap_vendor_type_t *type; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + if (strcaseeq(buf, "pubkey")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + return TRUE; + } + if (strcaseeq(buf, "psk")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); + return TRUE; + } + if (strcasepfx(buf, "xauth")) + { + pos = strchr(buf, '-'); + if (pos) + { + cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos)); + } + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH); + return TRUE; + } + if (strcasepfx(buf, "eap")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); + + type = eap_vendor_type_from_string(buf); + if (type) + { + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type); + if (type->vendor) + { + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor); + } + free(type); + } + return TRUE; + } + return FALSE; +} + +/** + * Parse identity; add as auth rule to config + */ +static bool parse_id(auth_cfg_t *cfg, auth_rule_t rule, chunk_t v) +{ + char buf[256]; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + cfg->add(cfg, rule, identification_create_from_string(buf)); + return TRUE; +} + +/** + * Parse IKE identity + */ +CALLBACK(parse_ike_id, bool, + auth_cfg_t *cfg, chunk_t v) +{ + return parse_id(cfg, AUTH_RULE_IDENTITY, v); +} + +/** + * Parse AAA identity + */ +CALLBACK(parse_aaa_id, bool, + auth_cfg_t *cfg, chunk_t v) +{ + return parse_id(cfg, AUTH_RULE_AAA_IDENTITY, v); +} + +/** + * Parse EAP identity + */ +CALLBACK(parse_eap_id, bool, + auth_cfg_t *cfg, chunk_t v) +{ + return parse_id(cfg, AUTH_RULE_EAP_IDENTITY, v); +} + +/** + * Parse XAuth identity + */ +CALLBACK(parse_xauth_id, bool, + auth_cfg_t *cfg, chunk_t v) +{ + return parse_id(cfg, AUTH_RULE_XAUTH_IDENTITY, v); +} + +/** + * Parse group membership + */ +CALLBACK(parse_group, bool, + auth_cfg_t *cfg, chunk_t v) +{ + return parse_id(cfg, AUTH_RULE_GROUP, v); +} + +/** + * Parse a certificate; add as auth rule to config + */ +static bool parse_cert(auth_cfg_t *cfg, auth_rule_t rule, chunk_t v) +{ + certificate_t *cert; + + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_PEM, v, BUILD_END); + if (cert) + { + cfg->add(cfg, rule, cert); + return TRUE; + } + return FALSE; +} + +/** + * Parse subject certificates + */ +CALLBACK(parse_certs, bool, + auth_cfg_t *cfg, chunk_t v) +{ + return parse_cert(cfg, AUTH_RULE_SUBJECT_CERT, v); +} + +/** + * Parse CA certificates + */ +CALLBACK(parse_cacerts, bool, + auth_cfg_t *cfg, chunk_t v) +{ + return parse_cert(cfg, AUTH_RULE_CA_CERT, v); +} + +/** + * Parse revocation status + */ +CALLBACK(parse_revocation, bool, + auth_cfg_t *cfg, chunk_t v) +{ + enum_map_t map[] = { + { "strict", VALIDATION_GOOD }, + { "ifuri", VALIDATION_SKIPPED }, + { "relaxed", VALIDATION_FAILED }, + }; + int d; + + if (parse_map(map, countof(map), &d, v)) + { + if (d != VALIDATION_FAILED) + { + cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, d); + } + return TRUE; + } + return FALSE; +} + +/** + * Parse list items to comma separated strings + */ +CALLBACK(parse_stringlist, bool, + char **out, chunk_t v) +{ + char *current; + + if (!chunk_printable(v, NULL, ' ')) + { + return FALSE; + } + current = *out; + if (current) + { + if (asprintf(out, "%s, %.*s", current, (int)v.len, v.ptr) == -1) + { + return FALSE; + } + free(current); + } + else + { + if (asprintf(out, "%.*s", (int)v.len, v.ptr) == -1) + { + return FALSE; + } + } + return TRUE; +} + +/** + * Parse an fragmentation_t + */ +CALLBACK(parse_frag, bool, + fragmentation_t *out, chunk_t v) +{ + enum_map_t map[] = { + { "yes", FRAGMENTATION_YES }, + { "no", FRAGMENTATION_NO }, + { "force", FRAGMENTATION_FORCE }, + }; + int d; + + if (parse_map(map, countof(map), &d, v)) + { + *out = d; + return TRUE; + } + return FALSE; +} + +/** + * Parse a cert_policy_t + */ +CALLBACK(parse_send_cert, bool, + cert_policy_t *out, chunk_t v) +{ + enum_map_t map[] = { + { "ifasked", CERT_SEND_IF_ASKED }, + { "always", CERT_ALWAYS_SEND }, + { "never", CERT_NEVER_SEND }, + }; + int d; + + if (parse_map(map, countof(map), &d, v)) + { + *out = d; + return TRUE; + } + return FALSE; +} + +/** + * Parse a unique_policy_t + */ +CALLBACK(parse_unique, bool, + unique_policy_t *out, chunk_t v) +{ + enum_map_t map[] = { + { "never", UNIQUE_NEVER }, + { "no", UNIQUE_NO }, + { "replace", UNIQUE_REPLACE }, + { "keep", UNIQUE_KEEP }, + }; + int d; + + if (parse_map(map, countof(map), &d, v)) + { + *out = d; + return TRUE; + } + return FALSE; +} + +/** + * Parse host_t into a list + */ +CALLBACK(parse_hosts, bool, + linked_list_t *list, chunk_t v) +{ + char buf[64]; + host_t *host; + + if (!vici_stringify(v, buf, sizeof(buf))) + { + return FALSE; + } + host = host_create_from_string(buf, 0); + if (!host) + { + return FALSE; + } + list->insert_last(list, host); + return TRUE; +} + +CALLBACK(child_li, bool, + child_data_t *child, vici_message_t *message, char *name, chunk_t value) +{ + parse_rule_t rules[] = { + { "ah_proposals", parse_ah_proposal, child->proposals }, + { "esp_proposals", parse_esp_proposal, child->proposals }, + { "local_ts", parse_ts, child->local_ts }, + { "remote_ts", parse_ts, child->remote_ts }, + }; + + return parse_rules(rules, countof(rules), name, value, + &child->request->reply); +} + +CALLBACK(child_kv, bool, + child_data_t *child, vici_message_t *message, char *name, chunk_t value) +{ + parse_rule_t rules[] = { + { "updown", parse_string, &child->updown }, + { "hostaccess", parse_bool, &child->hostaccess }, + { "mode", parse_mode, &child->mode }, + { "replay_window", parse_uint32, &child->replay_window }, + { "rekey_time", parse_time, &child->lft.time.rekey }, + { "life_time", parse_time, &child->lft.time.life }, + { "rand_time", parse_time, &child->lft.time.jitter }, + { "rekey_bytes", parse_bytes, &child->lft.bytes.rekey }, + { "life_bytes", parse_bytes, &child->lft.bytes.life }, + { "rand_bytes", parse_bytes, &child->lft.bytes.jitter }, + { "rekey_packets", parse_uint64, &child->lft.packets.rekey }, + { "life_packets", parse_uint64, &child->lft.packets.life }, + { "rand_packets", parse_uint64, &child->lft.packets.jitter }, + { "dpd_action", parse_action, &child->dpd_action }, + { "start_action", parse_action, &child->start_action }, + { "close_action", parse_action, &child->close_action }, + { "ipcomp", parse_bool, &child->ipcomp }, + { "inactivity", parse_time, &child->inactivity }, + { "reqid", parse_uint32, &child->reqid }, + { "mark_in", parse_mark, &child->mark_in }, + { "mark_out", parse_mark, &child->mark_out }, + { "tfc_padding", parse_tfc, &child->tfc }, + }; + + return parse_rules(rules, countof(rules), name, value, + &child->request->reply); +} + +CALLBACK(auth_li, bool, + auth_data_t *auth, vici_message_t *message, char *name, chunk_t value) +{ + parse_rule_t rules[] = { + { "groups", parse_group, auth->cfg }, + { "certs", parse_certs, auth->cfg }, + { "cacerts", parse_cacerts, auth->cfg }, + }; + + return parse_rules(rules, countof(rules), name, value, + &auth->request->reply); +} + +CALLBACK(auth_kv, bool, + auth_data_t *auth, vici_message_t *message, char *name, chunk_t value) +{ + parse_rule_t rules[] = { + { "auth", parse_auth, auth->cfg }, + { "id", parse_ike_id, auth->cfg }, + { "aaa_id", parse_aaa_id, auth->cfg }, + { "eap_id", parse_eap_id, auth->cfg }, + { "xauth_id", parse_xauth_id, auth->cfg }, + { "revocation", parse_revocation, auth->cfg }, + }; + + return parse_rules(rules, countof(rules), name, value, + &auth->request->reply); +} + +CALLBACK(peer_li, bool, + peer_data_t *peer, vici_message_t *message, char *name, chunk_t value) +{ + parse_rule_t rules[] = { + { "local_addrs", parse_stringlist, &peer->local_addrs }, + { "remote_addrs", parse_stringlist, &peer->remote_addrs }, + { "proposals", parse_ike_proposal, peer->proposals }, + { "vips", parse_hosts, peer->vips }, + { "pools", parse_stringlist, &peer->pools }, + }; + + return parse_rules(rules, countof(rules), name, value, + &peer->request->reply); +} + +CALLBACK(peer_kv, bool, + peer_data_t *peer, vici_message_t *message, char *name, chunk_t value) +{ + parse_rule_t rules[] = { + { "version", parse_uint32, &peer->version }, + { "aggressive", parse_bool, &peer->aggressive }, + { "pull", parse_bool, &peer->pull }, + { "encap", parse_bool, &peer->encap }, + { "mobike", parse_bool, &peer->mobike }, + { "dpd_delay", parse_time, &peer->dpd_delay }, + { "dpd_timeout", parse_time, &peer->dpd_timeout }, + { "fragmentation", parse_frag, &peer->fragmentation }, + { "send_certreq", parse_bool, &peer->send_certreq }, + { "send_cert", parse_send_cert, &peer->send_cert }, + { "keyingtries", parse_uint32, &peer->keyingtries }, + { "unique", parse_unique, &peer->unique }, + { "local_port", parse_uint32, &peer->local_port }, + { "remote_port", parse_uint32, &peer->remote_port }, + { "reauth_time", parse_time, &peer->reauth_time }, + { "rekey_time", parse_time, &peer->rekey_time }, + { "over_time", parse_time, &peer->over_time }, + { "rand_time", parse_time, &peer->rand_time }, + }; + + return parse_rules(rules, countof(rules), name, value, + &peer->request->reply); +} + +CALLBACK(children_sn, bool, + peer_data_t *peer, vici_message_t *message, vici_parse_context_t *ctx, + char *name) +{ + child_data_t child = { + .request = peer->request, + .proposals = linked_list_create(), + .local_ts = linked_list_create(), + .remote_ts = linked_list_create(), + .mode = MODE_TUNNEL, + .replay_window = REPLAY_UNDEFINED, + .dpd_action = ACTION_NONE, + .start_action = ACTION_NONE, + .close_action = ACTION_NONE, + .lft = { + .time = { + .rekey = LFT_DEFAULT_CHILD_REKEY, + .life = LFT_UNDEFINED, + .jitter = LFT_UNDEFINED, + }, + .bytes = { + .life = LFT_UNDEFINED, + .jitter = LFT_UNDEFINED, + }, + .packets = { + .life = LFT_UNDEFINED, + .jitter = LFT_UNDEFINED, + }, + } + }; + child_cfg_t *cfg; + proposal_t *proposal; + traffic_selector_t *ts; + + if (!message->parse(message, ctx, NULL, child_kv, child_li, &child)) + { + free_child_data(&child); + return FALSE; + } + + if (child.local_ts->get_count(child.local_ts) == 0) + { + child.local_ts->insert_last(child.local_ts, + traffic_selector_create_dynamic(0, 0, 65535)); + } + if (child.remote_ts->get_count(child.remote_ts) == 0) + { + child.remote_ts->insert_last(child.remote_ts, + traffic_selector_create_dynamic(0, 0, 65535)); + } + if (child.proposals->get_count(child.proposals) == 0) + { + proposal = proposal_create_default(PROTO_ESP); + if (proposal) + { + child.proposals->insert_last(child.proposals, proposal); + } + proposal = proposal_create_default_aead(PROTO_ESP); + if (proposal) + { + child.proposals->insert_last(child.proposals, proposal); + } + } + + /* if no hard lifetime specified, add one at soft lifetime + 10% */ + if (child.lft.time.life == LFT_UNDEFINED) + { + child.lft.time.life = child.lft.time.rekey * 110 / 100; + } + if (child.lft.bytes.life == LFT_UNDEFINED) + { + child.lft.bytes.life = child.lft.bytes.rekey * 110 / 100; + } + if (child.lft.packets.life == LFT_UNDEFINED) + { + child.lft.packets.life = child.lft.packets.rekey * 110 / 100; + } + /* if no rand time defined, use difference of hard and soft */ + if (child.lft.time.jitter == LFT_UNDEFINED) + { + child.lft.time.jitter = child.lft.time.life - + min(child.lft.time.life, child.lft.time.rekey); + } + if (child.lft.bytes.jitter == LFT_UNDEFINED) + { + child.lft.bytes.jitter = child.lft.bytes.life - + min(child.lft.bytes.life, child.lft.bytes.rekey); + } + if (child.lft.packets.jitter == LFT_UNDEFINED) + { + child.lft.packets.jitter = child.lft.packets.life - + min(child.lft.packets.life, child.lft.packets.rekey); + } + + log_child_data(&child, name); + + cfg = child_cfg_create(name, &child.lft, child.updown, + child.hostaccess, child.mode, child.start_action, + child.dpd_action, child.close_action, child.ipcomp, + child.inactivity, child.reqid, &child.mark_in, + &child.mark_out, child.tfc); + + if (child.replay_window != REPLAY_UNDEFINED) + { + cfg->set_replay_window(cfg, child.replay_window); + } + while (child.local_ts->remove_first(child.local_ts, + (void**)&ts) == SUCCESS) + { + cfg->add_traffic_selector(cfg, TRUE, ts); + } + while (child.remote_ts->remove_first(child.remote_ts, + (void**)&ts) == SUCCESS) + { + cfg->add_traffic_selector(cfg, FALSE, ts); + } + while (child.proposals->remove_first(child.proposals, + (void**)&proposal) == SUCCESS) + { + cfg->add_proposal(cfg, proposal); + } + + peer->children->insert_last(peer->children, cfg); + + free_child_data(&child); + + return TRUE; +} + +CALLBACK(peer_sn, bool, + peer_data_t *peer, vici_message_t *message, vici_parse_context_t *ctx, + char *name) +{ + if (strcaseeq(name, "children")) + { + return message->parse(message, ctx, children_sn, NULL, NULL, peer); + } + if (strcasepfx(name, "local") || + strcasepfx(name, "remote")) + { + auth_data_t auth = { + .request = peer->request, + .cfg = auth_cfg_create(), + }; + + if (!message->parse(message, ctx, NULL, auth_kv, auth_li, &auth)) + { + auth.cfg->destroy(auth.cfg); + return FALSE; + } + + if (strcasepfx(name, "local")) + { + peer->local->insert_last(peer->local, auth.cfg); + } + else + { + peer->remote->insert_last(peer->remote, auth.cfg); + } + return TRUE; + } + peer->request->reply = create_reply("invalid section: %s", name); + return FALSE; +} + +/** + * Find reqid of an existing CHILD_SA + */ +static u_int32_t find_reqid(child_cfg_t *cfg) +{ + enumerator_t *enumerator, *children; + child_sa_t *child_sa; + ike_sa_t *ike_sa; + u_int32_t reqid; + + reqid = charon->traps->find_reqid(charon->traps, cfg); + if (reqid) + { /* already trapped */ + return reqid; + } + + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); + while (!reqid && enumerator->enumerate(enumerator, &ike_sa)) + { + children = ike_sa->create_child_sa_enumerator(ike_sa); + while (children->enumerate(children, &child_sa)) + { + if (streq(cfg->get_name(cfg), child_sa->get_name(child_sa))) + { + reqid = child_sa->get_reqid(child_sa); + break; + } + } + children->destroy(children); + } + enumerator->destroy(enumerator); + return reqid; +} + +/** + * Perform start actions associated to a child config + */ +static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg, + child_cfg_t *child_cfg) +{ + switch (child_cfg->get_start_action(child_cfg)) + { + case ACTION_RESTART: + DBG1(DBG_CFG, "initiating '%s'", child_cfg->get_name(child_cfg)); + charon->controller->initiate(charon->controller, + peer_cfg->get_ref(peer_cfg), child_cfg->get_ref(child_cfg), + NULL, NULL, 0); + break; + case ACTION_ROUTE: + DBG1(DBG_CFG, "installing '%s'", child_cfg->get_name(child_cfg)); + switch (child_cfg->get_mode(child_cfg)) + { + case MODE_PASS: + case MODE_DROP: + charon->shunts->install(charon->shunts, child_cfg); + break; + default: + charon->traps->install(charon->traps, peer_cfg, child_cfg, + find_reqid(child_cfg)); + break; + } + break; + default: + break; + } +} + +/** + * Undo start actions associated to a child config + */ +static void clear_start_action(private_vici_config_t *this, + child_cfg_t *child_cfg) +{ + enumerator_t *enumerator, *children; + child_sa_t *child_sa; + ike_sa_t *ike_sa; + u_int32_t reqid = 0, *del; + array_t *reqids = NULL; + char *name; + + name = child_cfg->get_name(child_cfg); + switch (child_cfg->get_start_action(child_cfg)) + { + case ACTION_RESTART: + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + children = ike_sa->create_child_sa_enumerator(ike_sa); + while (children->enumerate(children, &child_sa)) + { + if (streq(name, child_sa->get_name(child_sa))) + { + reqid = child_sa->get_reqid(child_sa); + array_insert_create(&reqids, ARRAY_TAIL, &reqid); + } + } + children->destroy(children); + } + enumerator->destroy(enumerator); + + if (array_count(reqids)) + { + while (array_remove(reqids, ARRAY_HEAD, &del)) + { + DBG1(DBG_CFG, "closing '%s' #%u", name, *del); + charon->controller->terminate_child(charon->controller, + *del, NULL, NULL, 0); + } + array_destroy(reqids); + } + break; + case ACTION_ROUTE: + DBG1(DBG_CFG, "uninstalling '%s'", name); + switch (child_cfg->get_mode(child_cfg)) + { + case MODE_PASS: + case MODE_DROP: + charon->shunts->uninstall(charon->shunts, name); + break; + default: + enumerator = charon->traps->create_enumerator(charon->traps); + while (enumerator->enumerate(enumerator, NULL, &child_sa)) + { + if (streq(name, child_sa->get_name(child_sa))) + { + reqid = child_sa->get_reqid(child_sa); + break; + } + } + enumerator->destroy(enumerator); + if (reqid) + { + charon->traps->uninstall(charon->traps, reqid); + } + break; + } + break; + default: + break; + } +} + +/** + * Run start actions associated to all child configs of a peer config + */ +static void run_start_actions(private_vici_config_t *this, peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + child_cfg_t *child_cfg; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + run_start_action(this, peer_cfg, child_cfg); + } + enumerator->destroy(enumerator); +} + +/** + * Undo start actions associated to all child configs of a peer config + */ +static void clear_start_actions(private_vici_config_t *this, + peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + child_cfg_t *child_cfg; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + clear_start_action(this, child_cfg); + } + enumerator->destroy(enumerator); +} + +/** + * Replace children of a peer config by a new config + */ +static void replace_children(private_vici_config_t *this, + peer_cfg_t *from, peer_cfg_t *to) +{ + enumerator_t *enumerator; + child_cfg_t *child; + + enumerator = to->create_child_cfg_enumerator(to); + while (enumerator->enumerate(enumerator, &child)) + { + to->remove_child_cfg(to, enumerator); + clear_start_action(this, child); + child->destroy(child); + } + enumerator->destroy(enumerator); + + enumerator = from->create_child_cfg_enumerator(from); + while (enumerator->enumerate(enumerator, &child)) + { + from->remove_child_cfg(from, enumerator); + to->add_child_cfg(to, child); + run_start_action(this, to, child); + } + enumerator->destroy(enumerator); +} + +/** + * Merge/replace a peer config with existing configs + */ +static void merge_config(private_vici_config_t *this, peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + peer_cfg_t *current; + ike_cfg_t *ike_cfg; + bool merged = FALSE; + + this->lock->write_lock(this->lock); + + enumerator = this->conns->create_enumerator(this->conns); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(peer_cfg->get_name(peer_cfg), current->get_name(current))) + { + ike_cfg = current->get_ike_cfg(current); + if (peer_cfg->equals(peer_cfg, current) && + ike_cfg->equals(ike_cfg, peer_cfg->get_ike_cfg(peer_cfg))) + { + DBG1(DBG_CFG, "updated vici connection: %s", + peer_cfg->get_name(peer_cfg)); + replace_children(this, peer_cfg, current); + peer_cfg->destroy(peer_cfg); + } + else + { + DBG1(DBG_CFG, "replaced vici connection: %s", + peer_cfg->get_name(peer_cfg)); + this->conns->remove_at(this->conns, enumerator); + clear_start_actions(this, current); + current->destroy(current); + this->conns->insert_last(this->conns, peer_cfg); + run_start_actions(this, peer_cfg); + } + merged = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (!merged) + { + DBG1(DBG_CFG, "added vici connection: %s", peer_cfg->get_name(peer_cfg)); + this->conns->insert_last(this->conns, peer_cfg); + run_start_actions(this, peer_cfg); + } + + this->lock->unlock(this->lock); +} + +CALLBACK(config_sn, bool, + request_data_t *request, vici_message_t *message, + vici_parse_context_t *ctx, char *name) +{ + peer_data_t peer = { + .request = request, + .local = linked_list_create(), + .remote = linked_list_create(), + .vips = linked_list_create(), + .children = linked_list_create(), + .proposals = linked_list_create(), + .mobike = TRUE, + .send_certreq = TRUE, + .pull = TRUE, + .send_cert = CERT_SEND_IF_ASKED, + .version = IKE_ANY, + .remote_port = IKEV2_UDP_PORT, + .fragmentation = FRAGMENTATION_NO, + .unique = UNIQUE_NO, + .keyingtries = 1, + .rekey_time = LFT_DEFAULT_IKE_REKEY, + .over_time = LFT_UNDEFINED, + .rand_time = LFT_UNDEFINED, + }; + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + ike_cfg_t *ike_cfg; + child_cfg_t *child_cfg; + auth_cfg_t *auth_cfg; + proposal_t *proposal; + host_t *host; + char *str; + + DBG2(DBG_CFG, " conn %s:", name); + + if (!message->parse(message, ctx, peer_sn, peer_kv, peer_li, &peer)) + { + free_peer_data(&peer); + return FALSE; + } + + if (peer.local->get_count(peer.local) == 0) + { + free_peer_data(&peer); + peer.request->reply = create_reply("missing local auth config"); + return FALSE; + } + if (peer.remote->get_count(peer.remote) == 0) + { + auth_cfg = auth_cfg_create(); + peer.remote->insert_last(peer.remote, auth_cfg); + } + if (peer.proposals->get_count(peer.proposals) == 0) + { + proposal = proposal_create_default(PROTO_IKE); + if (proposal) + { + peer.proposals->insert_last(peer.proposals, proposal); + } + proposal = proposal_create_default_aead(PROTO_IKE); + if (proposal) + { + peer.proposals->insert_last(peer.proposals, proposal); + } + } + if (!peer.local_addrs) + { + peer.local_addrs = strdup("%any"); + } + if (!peer.remote_addrs) + { + peer.remote_addrs = strdup("%any"); + } + if (!peer.local_port) + { + peer.local_port = charon->socket->get_port(charon->socket, FALSE); + } + + if (peer.over_time == LFT_UNDEFINED) + { + /* default over_time to 10% of rekey/reauth time if not given */ + peer.over_time = max(peer.rekey_time, peer.reauth_time) / 10; + } + if (peer.rand_time == LFT_UNDEFINED) + { + /* default rand_time to over_time if not given */ + peer.rand_time = min(peer.over_time, + max(peer.rekey_time, peer.reauth_time) / 2); + } + + log_peer_data(&peer); + + ike_cfg = ike_cfg_create(peer.version, peer.send_certreq, peer.encap, + peer.local_addrs, peer.local_port, + peer.remote_addrs, peer.remote_port, + peer.fragmentation, 0); + peer_cfg = peer_cfg_create(name, ike_cfg, peer.send_cert, peer.unique, + peer.keyingtries, peer.rekey_time, peer.reauth_time, + peer.rand_time, peer.over_time, peer.mobike, + peer.aggressive, peer.pull, + peer.dpd_delay, peer.dpd_timeout, + FALSE, NULL, NULL); + + while (peer.local->remove_first(peer.local, + (void**)&auth_cfg) == SUCCESS) + { + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE); + } + while (peer.remote->remove_first(peer.remote, + (void**)&auth_cfg) == SUCCESS) + { + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE); + } + while (peer.children->remove_first(peer.children, + (void**)&child_cfg) == SUCCESS) + { + peer_cfg->add_child_cfg(peer_cfg, child_cfg); + } + while (peer.proposals->remove_first(peer.proposals, + (void**)&proposal) == SUCCESS) + { + ike_cfg->add_proposal(ike_cfg, proposal); + } + while (peer.vips->remove_first(peer.vips, (void**)&host) == SUCCESS) + { + peer_cfg->add_virtual_ip(peer_cfg, host); + } + if (peer.pools) + { + enumerator = enumerator_create_token(peer.pools, ",", " "); + while (enumerator->enumerate(enumerator, &str)) + { + peer_cfg->add_pool(peer_cfg, str); + } + enumerator->destroy(enumerator); + } + + free_peer_data(&peer); + + merge_config(request->this, peer_cfg); + + return TRUE; +} + +CALLBACK(load_conn, vici_message_t*, + private_vici_config_t *this, char *name, u_int id, vici_message_t *message) +{ + request_data_t request = { + .this = this, + }; + + if (!message->parse(message, NULL, config_sn, NULL, NULL, &request)) + { + if (request.reply) + { + return request.reply; + } + return create_reply("parsing request failed"); + } + return create_reply(NULL); +} + +CALLBACK(unload_conn, vici_message_t*, + private_vici_config_t *this, char *name, u_int id, vici_message_t *message) +{ + enumerator_t *enumerator; + peer_cfg_t *cfg; + bool found = FALSE; + char *conn; + + conn = message->get_str(message, NULL, "name"); + if (!conn) + { + return create_reply("missing connection name to unload"); + } + + this->lock->write_lock(this->lock); + enumerator = this->conns->create_enumerator(this->conns); + while (enumerator->enumerate(enumerator, &cfg)) + { + if (streq(cfg->get_name(cfg), conn)) + { + this->conns->remove_at(this->conns, enumerator); + cfg->destroy(cfg); + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + if (!found) + { + return create_reply("connection '%s' not found for unloading", conn); + } + return create_reply(NULL); +} + +CALLBACK(get_conns, vici_message_t*, + private_vici_config_t *this, char *name, u_int id, vici_message_t *message) +{ + vici_builder_t *builder; + enumerator_t *enumerator; + peer_cfg_t *cfg; + + builder = vici_builder_create(); + builder->begin_list(builder, "conns"); + + this->lock->read_lock(this->lock); + enumerator = this->conns->create_enumerator(this->conns); + while (enumerator->enumerate(enumerator, &cfg)) + { + builder->add_li(builder, "%s", cfg->get_name(cfg)); + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + builder->end_list(builder); + + return builder->finalize(builder); +} + +static void manage_command(private_vici_config_t *this, + char *name, vici_command_cb_t cb, bool reg) +{ + this->dispatcher->manage_command(this->dispatcher, name, + reg ? cb : NULL, this); +} + +/** + * (Un-)register dispatcher functions + */ +static void manage_commands(private_vici_config_t *this, bool reg) +{ + manage_command(this, "load-conn", load_conn, reg); + manage_command(this, "unload-conn", unload_conn, reg); + manage_command(this, "get-conns", get_conns, reg); +} + +METHOD(vici_config_t, destroy, void, + private_vici_config_t *this) +{ + manage_commands(this, FALSE); + this->conns->destroy_offset(this->conns, offsetof(peer_cfg_t, destroy)); + this->lock->destroy(this->lock); + free(this); +} + +/** + * See header + */ +vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher) +{ + private_vici_config_t *this; + + INIT(this, + .public = { + .backend = { + .create_peer_cfg_enumerator = _create_peer_cfg_enumerator, + .create_ike_cfg_enumerator = _create_ike_cfg_enumerator, + .get_peer_cfg_by_name = _get_peer_cfg_by_name, + }, + .destroy = _destroy, + }, + .dispatcher = dispatcher, + .conns = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + manage_commands(this, TRUE); + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_config.h b/src/libcharon/plugins/vici/vici_config.h new file mode 100644 index 000000000..820d5f300 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_config.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_config vici_config + * @{ @ingroup vici + */ + +#ifndef VICI_CONFIG_H_ +#define VICI_CONFIG_H_ + +#include "vici_dispatcher.h" + +#include <config/backend.h> + +typedef struct vici_config_t vici_config_t; + +/** + * In-memory configuration backend, managed by VICI. + */ +struct vici_config_t { + + /** + * Implements a configuraiton backend. + */ + backend_t backend; + + /** + * Destroy a vici_config_t. + */ + void (*destroy)(vici_config_t *this); +}; +/** + * Create a vici_config instance. + * + * @param dispatcher dispatcher to receive requests from + * @return config backend + */ +vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher); + +#endif /** VICI_CONFIG_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c new file mode 100644 index 000000000..3cd008162 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_control.c @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_control.h" +#include "vici_builder.h" + +#include <inttypes.h> + +#include <daemon.h> +#include <collections/array.h> + +typedef struct private_vici_control_t private_vici_control_t; + +/** + * Private data of an vici_control_t object. + */ +struct private_vici_control_t { + + /** + * Public vici_control_t interface. + */ + vici_control_t public; + + /** + * Dispatcher + */ + vici_dispatcher_t *dispatcher; +}; + +/** + * Log callback helper data + */ +typedef struct { + /** dispatcher to send log messages over */ + vici_dispatcher_t *dispatcher; + /** connection ID to send messages to */ + u_int id; + /** loglevel */ + level_t level; + /** prevent recursive log */ + u_int recursive; +} log_info_t; + +/** + * Log using vici event messages + */ +static bool log_vici(log_info_t *info, debug_t group, level_t level, + ike_sa_t *ike_sa, char *text) +{ + if (level <= info->level) + { + if (info->recursive++ == 0) + { + vici_message_t *message; + vici_builder_t *builder; + + builder = vici_builder_create(); + builder->add_kv(builder, "group", "%N", debug_names, group); + builder->add_kv(builder, "level", "%d", level); + if (ike_sa) + { + builder->add_kv(builder, "ikesa-name", "%s", + ike_sa->get_name(ike_sa)); + builder->add_kv(builder, "ikesa-uniqueid", "%u", + ike_sa->get_unique_id(ike_sa)); + } + builder->add_kv(builder, "msg", "%s", text); + + message = builder->finalize(builder); + if (message) + { + info->dispatcher->raise_event(info->dispatcher, "control-log", + info->id, message); + } + } + info->recursive--; + } + return TRUE; +} + +/** + * Send a (error) reply message + */ +static vici_message_t* send_reply(private_vici_control_t *this, char *fmt, ...) +{ + vici_builder_t *builder; + va_list args; + + builder = vici_builder_create(); + builder->add_kv(builder, "success", fmt ? "no" : "yes"); + if (fmt) + { + va_start(args, fmt); + builder->vadd_kv(builder, "errmsg", fmt, args); + va_end(args); + } + return builder->finalize(builder); +} + +/** + * Get the child_cfg having name from peer_cfg + */ +static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) +{ + child_cfg_t *current, *found = NULL; + enumerator_t *enumerator; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(current->get_name(current), name)) + { + found = current; + found->get_ref(found); + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * Find a peer/child config from a child config name + */ +static child_cfg_t* find_child_cfg(char *name, peer_cfg_t **out) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + + enumerator = charon->backends->create_peer_cfg_enumerator( + charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + child_cfg = get_child_from_peer(peer_cfg, name); + if (child_cfg) + { + *out = peer_cfg->get_ref(peer_cfg); + break; + } + } + enumerator->destroy(enumerator); + + return child_cfg; +} + +CALLBACK(initiate, vici_message_t*, + private_vici_control_t *this, char *name, u_int id, vici_message_t *request) +{ + child_cfg_t *child_cfg = NULL; + peer_cfg_t *peer_cfg; + char *child; + u_int timeout; + log_info_t log = { + .dispatcher = this->dispatcher, + .id = id, + }; + + child = request->get_str(request, NULL, "child"); + timeout = request->get_int(request, 0, "timeout"); + log.level = request->get_int(request, 1, "loglevel"); + + if (!child) + { + return send_reply(this, "missing configuration name"); + } + + DBG1(DBG_CFG, "vici initiate '%s'", child); + + child_cfg = find_child_cfg(child, &peer_cfg); + if (!child_cfg) + { + return send_reply(this, "CHILD_SA config '%s' not found", child); + } + switch (charon->controller->initiate(charon->controller, + peer_cfg, child_cfg, (controller_cb_t)log_vici, &log, timeout)) + { + case SUCCESS: + return send_reply(this, NULL); + case OUT_OF_RES: + return send_reply(this, "CHILD_SA '%s' not established after %dms", + child, timeout); + case FAILED: + default: + return send_reply(this, "establishing CHILD_SA '%s' failed", child); + } +} + +CALLBACK(terminate, vici_message_t*, + private_vici_control_t *this, char *name, u_int id, vici_message_t *request) +{ + enumerator_t *enumerator, *isas, *csas; + char *child, *ike, *errmsg = NULL; + u_int timeout, child_id, ike_id, current, *del, done = 0; + ike_sa_t *ike_sa; + child_sa_t *child_sa; + array_t *ids; + vici_builder_t *builder; + log_info_t log = { + .dispatcher = this->dispatcher, + .id = id, + }; + + child = request->get_str(request, NULL, "child"); + ike = request->get_str(request, NULL, "ike"); + child_id = request->get_int(request, 0, "child-id"); + ike_id = request->get_int(request, 0, "ike-id"); + timeout = request->get_int(request, 0, "timeout"); + log.level = request->get_int(request, 1, "loglevel"); + + if (!child && !ike && !ike_id && !child_id) + { + return send_reply(this, "missing terminate selector"); + } + + if (ike_id) + { + DBG1(DBG_CFG, "vici terminate IKE_SA #%d", ike_id); + } + if (child_id) + { + DBG1(DBG_CFG, "vici terminate CHILD_SA #%d", child_id); + } + if (ike) + { + DBG1(DBG_CFG, "vici terminate IKE_SA '%s'", ike); + } + if (child) + { + DBG1(DBG_CFG, "vici terminate CHILD_SA '%s'", child); + } + + ids = array_create(sizeof(u_int), 0); + + isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE); + while (isas->enumerate(isas, &ike_sa)) + { + if (child || child_id) + { + if (ike && !streq(ike, ike_sa->get_name(ike_sa))) + { + continue; + } + if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa)) + { + continue; + } + csas = ike_sa->create_child_sa_enumerator(ike_sa); + while (csas->enumerate(csas, &child_sa)) + { + if (child && !streq(child, child_sa->get_name(child_sa))) + { + continue; + } + if (child_id && child_sa->get_reqid(child_sa) != child_id) + { + continue; + } + current = child_sa->get_reqid(child_sa); + array_insert(ids, ARRAY_TAIL, ¤t); + } + csas->destroy(csas); + } + else if (ike && streq(ike, ike_sa->get_name(ike_sa))) + { + current = ike_sa->get_unique_id(ike_sa); + array_insert(ids, ARRAY_TAIL, ¤t); + } + else if (ike_id && ike_id == ike_sa->get_unique_id(ike_sa)) + { + array_insert(ids, ARRAY_TAIL, &ike_id); + } + } + isas->destroy(isas); + + enumerator = array_create_enumerator(ids); + while (enumerator->enumerate(enumerator, &del)) + { + if (child || child_id) + { + if (charon->controller->terminate_child(charon->controller, *del, + (controller_cb_t)log_vici, &log, timeout) == SUCCESS) + { + done++; + } + } + else + { + if (charon->controller->terminate_ike(charon->controller, *del, + (controller_cb_t)log_vici, &log, timeout) == SUCCESS) + { + done++; + } + } + } + enumerator->destroy(enumerator); + + builder = vici_builder_create(); + if (array_count(ids) == 0) + { + errmsg = "no matching SAs to terminate found"; + } + else if (done < array_count(ids)) + { + if (array_count(ids) == 1) + { + errmsg = "terminating SA failed"; + } + else + { + errmsg = "not all matching SAs could be terminated"; + } + } + builder->add_kv(builder, "success", errmsg ? "no" : "yes"); + builder->add_kv(builder, "matches", "%u", array_count(ids)); + builder->add_kv(builder, "terminated", "%u", done); + if (errmsg) + { + builder->add_kv(builder, "errmsg", "%s", errmsg); + } + array_destroy(ids); + return builder->finalize(builder); +} + +/** + * Find reqid of an existing CHILD_SA + */ +static u_int32_t find_reqid(child_cfg_t *cfg) +{ + enumerator_t *enumerator, *children; + child_sa_t *child_sa; + ike_sa_t *ike_sa; + u_int32_t reqid; + + reqid = charon->traps->find_reqid(charon->traps, cfg); + if (reqid) + { /* already trapped */ + return reqid; + } + + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); + while (!reqid && enumerator->enumerate(enumerator, &ike_sa)) + { + children = ike_sa->create_child_sa_enumerator(ike_sa); + while (children->enumerate(children, &child_sa)) + { + if (streq(cfg->get_name(cfg), child_sa->get_name(child_sa))) + { + reqid = child_sa->get_reqid(child_sa); + break; + } + } + children->destroy(children); + } + enumerator->destroy(enumerator); + return reqid; +} + +CALLBACK(install, vici_message_t*, + private_vici_control_t *this, char *name, u_int id, vici_message_t *request) +{ + child_cfg_t *child_cfg = NULL; + peer_cfg_t *peer_cfg; + char *child; + bool ok; + + child = request->get_str(request, NULL, "child"); + if (!child) + { + return send_reply(this, "missing configuration name"); + } + + DBG1(DBG_CFG, "vici install '%s'", child); + + child_cfg = find_child_cfg(child, &peer_cfg); + if (!child_cfg) + { + return send_reply(this, "configuration name not found"); + } + switch (child_cfg->get_mode(child_cfg)) + { + case MODE_PASS: + case MODE_DROP: + ok = charon->shunts->install(charon->shunts, child_cfg); + break; + default: + ok = charon->traps->install(charon->traps, peer_cfg, child_cfg, + find_reqid(child_cfg)); + break; + } + peer_cfg->destroy(peer_cfg); + child_cfg->destroy(child_cfg); + + return send_reply(this, ok ? NULL : "installing policy '%s' failed", child); +} + +CALLBACK(uninstall, vici_message_t*, + private_vici_control_t *this, char *name, u_int id, vici_message_t *request) +{ + child_sa_t *child_sa; + enumerator_t *enumerator; + u_int32_t reqid = 0; + char *child; + + child = request->get_str(request, NULL, "child"); + if (!child) + { + return send_reply(this, "missing configuration name"); + } + + DBG1(DBG_CFG, "vici uninstall '%s'", child); + + if (charon->shunts->uninstall(charon->shunts, child)) + { + return send_reply(this, NULL); + } + + enumerator = charon->traps->create_enumerator(charon->traps); + while (enumerator->enumerate(enumerator, NULL, &child_sa)) + { + if (streq(child, child_sa->get_name(child_sa))) + { + reqid = child_sa->get_reqid(child_sa); + break; + } + } + enumerator->destroy(enumerator); + + if (reqid) + { + if (charon->traps->uninstall(charon->traps, reqid)) + { + return send_reply(this, NULL); + } + return send_reply(this, "uninstalling policy '%s' failed", child); + } + return send_reply(this, "policy '%s' not found", child); +} + +static void manage_command(private_vici_control_t *this, + char *name, vici_command_cb_t cb, bool reg) +{ + this->dispatcher->manage_command(this->dispatcher, name, + reg ? cb : NULL, this); +} + +/** + * (Un-)register dispatcher functions + */ +static void manage_commands(private_vici_control_t *this, bool reg) +{ + manage_command(this, "initiate", initiate, reg); + manage_command(this, "terminate", terminate, reg); + manage_command(this, "install", install, reg); + manage_command(this, "uninstall", uninstall, reg); + this->dispatcher->manage_event(this->dispatcher, "control-log", reg); +} + +METHOD(vici_control_t, destroy, void, + private_vici_control_t *this) +{ + manage_commands(this, FALSE); + free(this); +} + +/** + * See header + */ +vici_control_t *vici_control_create(vici_dispatcher_t *dispatcher) +{ + private_vici_control_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + }, + .dispatcher = dispatcher, + ); + + manage_commands(this, TRUE); + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_control.h b/src/libcharon/plugins/vici/vici_control.h new file mode 100644 index 000000000..71a13a074 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_control.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_control vici_control + * @{ @ingroup vici + */ + +#include "vici_dispatcher.h" + +#ifndef VICI_CONTROL_H_ +#define VICI_CONTROL_H_ + +typedef struct vici_control_t vici_control_t; + +/** + * Control helper, provides initiate/terminate and other commands. + */ +struct vici_control_t { + + /** + * Destroy a vici_control_t. + */ + void (*destroy)(vici_control_t *this); +}; + +/** + * Create a vici_control instance. + * + * @param dispatcher dispatcher to receive requests from + * @return query handler + */ +vici_control_t *vici_control_create(vici_dispatcher_t *dispatcher); + +#endif /** VICI_CONTROL_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c new file mode 100644 index 000000000..cc6434b62 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_cred.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_cred.h" +#include "vici_builder.h" + +#include <credentials/sets/mem_cred.h> +#include <credentials/certificates/ac.h> +#include <credentials/certificates/crl.h> +#include <credentials/certificates/x509.h> + +typedef struct private_vici_cred_t private_vici_cred_t; + +/** + * Private data of an vici_cred_t object. + */ +struct private_vici_cred_t { + + /** + * Public vici_cred_t interface. + */ + vici_cred_t public; + + /** + * Dispatcher + */ + vici_dispatcher_t *dispatcher; + + /** + * credentials + */ + mem_cred_t *creds; +}; + +/** + * Create a (error) reply message + */ +static vici_message_t* create_reply(char *fmt, ...) +{ + vici_builder_t *builder; + va_list args; + + builder = vici_builder_create(); + builder->add_kv(builder, "success", fmt ? "no" : "yes"); + if (fmt) + { + va_start(args, fmt); + builder->vadd_kv(builder, "errmsg", fmt, args); + va_end(args); + } + return builder->finalize(builder); +} + +CALLBACK(load_cert, vici_message_t*, + private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) +{ + certificate_type_t type; + x509_flag_t required_flags = 0, additional_flags = 0; + certificate_t *cert; + x509_t *x509; + chunk_t data; + char *str; + + str = message->get_str(message, NULL, "type"); + if (!str) + { + return create_reply("certificate type missing"); + } + if (strcaseeq(str, "x509")) + { + type = CERT_X509; + } + else if (strcaseeq(str, "x509ca")) + { + type = CERT_X509; + required_flags = X509_CA; + } + else if (strcaseeq(str, "x509aa")) + { + type = CERT_X509; + additional_flags = X509_AA; + } + else if (strcaseeq(str, "x509crl")) + { + type = CERT_X509_CRL; + } + else if (strcaseeq(str, "x509ac")) + { + type = CERT_X509_AC; + } + else + { + return create_reply("invalid certificate type: %s", str); + } + data = message->get_value(message, chunk_empty, "data"); + if (!data.len) + { + return create_reply("certificate data missing"); + } + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, type, + BUILD_BLOB_PEM, data, + BUILD_X509_FLAG, additional_flags, + BUILD_END); + if (!cert) + { + return create_reply("parsing %N certificate failed", + certificate_type_names, type); + } + if (cert->get_type(cert) == CERT_X509) + { + x509 = (x509_t*)cert; + + if ((required_flags & x509->get_flags(x509)) != required_flags) + { + cert->destroy(cert); + return create_reply("certificate misses required flag, rejected"); + } + } + + DBG1(DBG_CFG, "loaded certificate '%Y'", cert->get_subject(cert)); + + this->creds->add_cert(this->creds, TRUE, cert); + + return create_reply(NULL); +} + +CALLBACK(load_key, vici_message_t*, + private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) +{ + key_type_t type; + private_key_t *key; + chunk_t data; + char *str; + + str = message->get_str(message, NULL, "type"); + if (!str) + { + return create_reply("key type missing"); + } + if (strcaseeq(str, "any")) + { + type = KEY_ANY; + } + else if (strcaseeq(str, "rsa")) + { + type = KEY_RSA; + } + else if (strcaseeq(str, "ecdsa")) + { + type = KEY_ECDSA; + } + else + { + return create_reply("invalid key type: %s", str); + } + data = message->get_value(message, chunk_empty, "data"); + if (!data.len) + { + return create_reply("key data missing"); + } + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_BLOB_PEM, data, BUILD_END); + if (!key) + { + return create_reply("parsing %N private key failed", + key_type_names, type); + } + + DBG1(DBG_CFG, "loaded %N private key", key_type_names, type); + + this->creds->add_key(this->creds, key); + + return create_reply(NULL); +} + +CALLBACK(shared_owners, bool, + linked_list_t *owners, vici_message_t *message, char *name, chunk_t value) +{ + if (streq(name, "owners")) + { + char buf[256]; + + if (!vici_stringify(value, buf, sizeof(buf))) + { + return FALSE; + } + owners->insert_last(owners, identification_create_from_string(buf)); + } + return TRUE; +} + +CALLBACK(load_shared, vici_message_t*, + private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) +{ + shared_key_type_t type; + linked_list_t *owners; + chunk_t data; + char *str, buf[512] = ""; + enumerator_t *enumerator; + identification_t *owner; + int len; + + str = message->get_str(message, NULL, "type"); + if (!str) + { + return create_reply("shared key type missing"); + } + if (strcaseeq(str, "ike")) + { + type = SHARED_IKE; + } + else if (strcaseeq(str, "eap") || streq(str, "xauth")) + { + type = SHARED_EAP; + } + else + { + return create_reply("invalid shared key type: %s", str); + } + data = message->get_value(message, chunk_empty, "data"); + if (!data.len) + { + return create_reply("shared key data missing"); + } + + owners = linked_list_create(); + if (!message->parse(message, NULL, NULL, NULL, shared_owners, owners)) + { + owners->destroy_offset(owners, offsetof(identification_t, destroy)); + return create_reply("parsing shared key owners failed"); + } + if (owners->get_count(owners) == 0) + { + owners->insert_last(owners, identification_create_from_string("%any")); + } + + enumerator = owners->create_enumerator(owners); + while (enumerator->enumerate(enumerator, &owner)) + { + len = strlen(buf); + if (len < sizeof(buf)) + { + snprintf(buf + len, sizeof(buf) - len, "%s'%Y'", + len ? ", " : "", owner); + } + } + enumerator->destroy(enumerator); + + DBG1(DBG_CFG, "loaded %N shared key for: %s", + shared_key_type_names, type, buf); + + this->creds->add_shared_list(this->creds, + shared_key_create(type, chunk_clone(data)), owners); + + return create_reply(NULL); +} + +CALLBACK(clear_creds, vici_message_t*, + private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) +{ + vici_builder_t *builder; + + this->creds->clear(this->creds); + lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); + + builder = vici_builder_create(); + return builder->finalize(builder); +} + +static void manage_command(private_vici_cred_t *this, + char *name, vici_command_cb_t cb, bool reg) +{ + this->dispatcher->manage_command(this->dispatcher, name, + reg ? cb : NULL, this); +} + +/** + * (Un-)register dispatcher functions + */ +static void manage_commands(private_vici_cred_t *this, bool reg) +{ + manage_command(this, "clear-creds", clear_creds, reg); + manage_command(this, "load-cert", load_cert, reg); + manage_command(this, "load-key", load_key, reg); + manage_command(this, "load-shared", load_shared, reg); +} + +METHOD(vici_cred_t, destroy, void, + private_vici_cred_t *this) +{ + manage_commands(this, FALSE); + + lib->credmgr->remove_set(lib->credmgr, &this->creds->set); + this->creds->destroy(this->creds); + free(this); +} + +/** + * See header + */ +vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher) +{ + private_vici_cred_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + }, + .dispatcher = dispatcher, + .creds = mem_cred_create(), + ); + + lib->credmgr->add_set(lib->credmgr, &this->creds->set); + + manage_commands(this, TRUE); + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_cred.h b/src/libcharon/plugins/vici/vici_cred.h new file mode 100644 index 000000000..e109a27da --- /dev/null +++ b/src/libcharon/plugins/vici/vici_cred.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_cred vici_cred + * @{ @ingroup vici + */ + +#ifndef VICI_CRED_H_ +#define VICI_CRED_H_ + +#include "vici_dispatcher.h" + +typedef struct vici_cred_t vici_cred_t; + +/** + * In-memory credential backend, managed by VICI. + */ +struct vici_cred_t { + + /** + * Destroy a vici_cred_t. + */ + void (*destroy)(vici_cred_t *this); +}; + +/** + * Create a vici_cred instance. + * + * @param dispatcher dispatcher to receive requests from + * @return credential backend + */ +vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher); + +#endif /** VICI_CRED_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_dispatcher.c b/src/libcharon/plugins/vici/vici_dispatcher.c new file mode 100644 index 000000000..6db36fbe0 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_dispatcher.c @@ -0,0 +1,524 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_dispatcher.h" +#include "vici_socket.h" + +#include <bio/bio_reader.h> +#include <bio/bio_writer.h> +#include <threading/mutex.h> +#include <threading/condvar.h> +#include <threading/thread.h> +#include <collections/array.h> +#include <collections/hashtable.h> + +typedef struct private_vici_dispatcher_t private_vici_dispatcher_t; + +/** + * Private data of an vici_dispatcher_t object. + */ +struct private_vici_dispatcher_t { + + /** + * Public vici_dispatcher_t interface. + */ + vici_dispatcher_t public; + + /** + * Socket to send/receive messages + */ + vici_socket_t *socket; + + /** + * List of registered commands (char* => command_t*) + */ + hashtable_t *cmds; + + /** + * List of known events, and registered clients (char* => event_t*) + */ + hashtable_t *events; + + /** + * Mutex to lock hashtables + */ + mutex_t *mutex; + + /** + * Condvar to signal command termination + */ + condvar_t *cond; +}; + +/** + * Registered command + */ +typedef struct { + /** command name */ + char *name; + /** callback for command */ + vici_command_cb_t cb; + /** user data to pass to callback */ + void *user; + /** command currently in use? */ + u_int uses; +} command_t; + +/** + * Registered event + */ +typedef struct { + /** event name */ + char *name; + /** registered clients, as u_int */ + array_t *clients; + /** event currently in use? */ + u_int uses; +} event_t; + +/** + * Send a operation code, optionally with name and message + */ +static void send_op(private_vici_dispatcher_t *this, u_int id, + vici_operation_t op, char *name, vici_message_t *message) +{ + bio_writer_t *writer; + u_int len; + + len = sizeof(u_int8_t); + if (name) + { + len += sizeof(u_int8_t) + strlen(name); + } + if (message) + { + len += message->get_encoding(message).len; + } + writer = bio_writer_create(len); + writer->write_uint8(writer, op); + if (name) + { + writer->write_data8(writer, chunk_from_str(name)); + } + if (message) + { + writer->write_data(writer, message->get_encoding(message)); + } + this->socket->send(this->socket, id, writer->extract_buf(writer)); + writer->destroy(writer); +} + +/** + * Register client for event + */ +static void register_event(private_vici_dispatcher_t *this, char *name, + u_int id) +{ + event_t *event; + + this->mutex->lock(this->mutex); + while (TRUE) + { + event = this->events->get(this->events, name); + if (!event) + { + break; + } + if (!event->uses) + { + array_insert(event->clients, ARRAY_TAIL, &id); + break; + } + this->cond->wait(this->cond, this->mutex); + } + this->mutex->unlock(this->mutex); + + if (event) + { + DBG2(DBG_CFG, "vici client %u registered for: %s", id, name); + send_op(this, id, VICI_EVENT_CONFIRM, NULL, NULL); + } + else + { + DBG1(DBG_CFG, "vici client %u invalid registration: %s", id, name); + send_op(this, id, VICI_EVENT_UNKNOWN, NULL, NULL); + } +} + +/** + * Unregister client for event + */ +static void unregister_event(private_vici_dispatcher_t *this, char *name, + u_int id) +{ + enumerator_t *enumerator; + event_t *event; + u_int *current; + bool found = FALSE; + + this->mutex->lock(this->mutex); + while (TRUE) + { + event = this->events->get(this->events, name); + if (!event) + { + break; + } + if (!event->uses) + { + enumerator = array_create_enumerator(event->clients); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (*current == id) + { + array_remove_at(event->clients, enumerator); + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + break; + } + this->cond->wait(this->cond, this->mutex); + } + this->mutex->unlock(this->mutex); + + DBG2(DBG_CFG, "vici client %u unregistered for: %s", id, name); + + if (found) + { + send_op(this, id, VICI_EVENT_CONFIRM, NULL, NULL); + } + else + { + send_op(this, id, VICI_EVENT_UNKNOWN, NULL, NULL); + } +} + +/** + * Data to release on thread cancellation + */ +typedef struct { + private_vici_dispatcher_t *this; + command_t *cmd; + vici_message_t *request; +} release_data_t; + +/** + * Release command after execution/cancellation + */ +CALLBACK(release_command, void, + release_data_t *release) +{ + release->request->destroy(release->request); + + release->this->mutex->lock(release->this->mutex); + if (--release->cmd->uses == 0) + { + release->this->cond->broadcast(release->this->cond); + } + release->this->mutex->unlock(release->this->mutex); + + free(release); +} + +/** + * Process a request message + */ +void process_request(private_vici_dispatcher_t *this, char *name, u_int id, + chunk_t data) +{ + vici_message_t *response = NULL; + release_data_t *release; + command_t *cmd; + + this->mutex->lock(this->mutex); + cmd = this->cmds->get(this->cmds, name); + if (cmd) + { + cmd->uses++; + } + this->mutex->unlock(this->mutex); + + if (cmd) + { + INIT(release, + .this = this, + .cmd = cmd, + ); + + DBG2(DBG_CFG, "vici client %u requests: %s", id, name); + + thread_cleanup_push(release_command, release); + + release->request = vici_message_create_from_data(data, FALSE); + response = release->cmd->cb(cmd->user, cmd->name, id, release->request); + + thread_cleanup_pop(TRUE); + + if (response) + { + send_op(this, id, VICI_CMD_RESPONSE, NULL, response); + response->destroy(response); + } + } + else + { + DBG1(DBG_CFG, "vici client %u invalid request: %s", id, name); + send_op(this, id, VICI_CMD_UNKNOWN, NULL, NULL); + } +} + +CALLBACK(inbound, void, + private_vici_dispatcher_t *this, u_int id, chunk_t data) +{ + bio_reader_t *reader; + chunk_t chunk; + u_int8_t type; + char name[257]; + + reader = bio_reader_create(data); + if (reader->read_uint8(reader, &type)) + { + switch (type) + { + case VICI_EVENT_REGISTER: + if (reader->read_data8(reader, &chunk) && + vici_stringify(chunk, name, sizeof(name))) + { + register_event(this, name, id); + } + else + { + DBG1(DBG_CFG, "invalid vici register message"); + } + break; + case VICI_EVENT_UNREGISTER: + if (reader->read_data8(reader, &chunk) && + vici_stringify(chunk, name, sizeof(name))) + { + unregister_event(this, name, id); + } + else + { + DBG1(DBG_CFG, "invalid vici unregister message"); + } + break; + case VICI_CMD_REQUEST: + if (reader->read_data8(reader, &chunk) && + vici_stringify(chunk, name, sizeof(name))) + { + thread_cleanup_push((void*)reader->destroy, reader); + process_request(this, name, id, reader->peek(reader)); + thread_cleanup_pop(FALSE); + } + else + { + DBG1(DBG_CFG, "invalid vici request message"); + } + break; + case VICI_CMD_RESPONSE: + case VICI_EVENT_CONFIRM: + case VICI_EVENT_UNKNOWN: + case VICI_EVENT: + default: + DBG1(DBG_CFG, "unsupported vici operation: %u", type); + break; + } + } + else + { + DBG1(DBG_CFG, "invalid vici message"); + } + reader->destroy(reader); +} + +CALLBACK(connect_, void, + private_vici_dispatcher_t *this, u_int id) +{ + DBG2(DBG_CFG, "vici client %u connected", id); +} + +CALLBACK(disconnect, void, + private_vici_dispatcher_t *this, u_int id) +{ + enumerator_t *events, *ids; + event_t *event; + u_int *current; + + /* deregister client from all events */ + this->mutex->lock(this->mutex); + events = this->events->create_enumerator(this->events); + while (events->enumerate(events, NULL, &event)) + { + while (event->uses) + { + this->cond->wait(this->cond, this->mutex); + } + ids = array_create_enumerator(event->clients); + while (ids->enumerate(ids, ¤t)) + { + if (id == *current) + { + array_remove_at(event->clients, ids); + } + } + ids->destroy(ids); + } + events->destroy(events); + this->mutex->unlock(this->mutex); + + DBG2(DBG_CFG, "vici client %u disconnected", id); +} + +METHOD(vici_dispatcher_t, manage_command, void, + private_vici_dispatcher_t *this, char *name, + vici_command_cb_t cb, void *user) +{ + command_t *cmd; + + this->mutex->lock(this->mutex); + if (cb) + { + INIT(cmd, + .name = strdup(name), + .cb = cb, + .user = user, + ); + cmd = this->cmds->put(this->cmds, cmd->name, cmd); + } + else + { + cmd = this->cmds->remove(this->cmds, name); + } + if (cmd) + { + while (cmd->uses) + { + this->cond->wait(this->cond, this->mutex); + } + free(cmd->name); + free(cmd); + } + this->mutex->unlock(this->mutex); +} + +METHOD(vici_dispatcher_t, manage_event, void, + private_vici_dispatcher_t *this, char *name, bool reg) +{ + event_t *event; + + this->mutex->lock(this->mutex); + if (reg) + { + INIT(event, + .name = strdup(name), + .clients = array_create(sizeof(u_int), 0), + ); + event = this->events->put(this->events, event->name, event); + } + else + { + event = this->events->remove(this->events, name); + } + if (event) + { + while (event->uses) + { + this->cond->wait(this->cond, this->mutex); + } + array_destroy(event->clients); + free(event->name); + free(event); + } + this->mutex->unlock(this->mutex); +} + +METHOD(vici_dispatcher_t, raise_event, void, + private_vici_dispatcher_t *this, char *name, u_int id, + vici_message_t *message) +{ + enumerator_t *enumerator; + event_t *event; + u_int *current; + + this->mutex->lock(this->mutex); + event = this->events->get(this->events, name); + if (event) + { + event->uses++; + this->mutex->unlock(this->mutex); + + enumerator = array_create_enumerator(event->clients); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (id == 0 || id == *current) + { + send_op(this, *current, VICI_EVENT, name, message); + } + } + enumerator->destroy(enumerator); + + this->mutex->lock(this->mutex); + if (--event->uses == 0) + { + this->cond->broadcast(this->cond); + } + } + this->mutex->unlock(this->mutex); + + message->destroy(message); +} + +METHOD(vici_dispatcher_t, destroy, void, + private_vici_dispatcher_t *this) +{ + DESTROY_IF(this->socket); + this->mutex->destroy(this->mutex); + this->cond->destroy(this->cond); + this->cmds->destroy(this->cmds); + this->events->destroy(this->events); + free(this); +} + +/** + * See header + */ +vici_dispatcher_t *vici_dispatcher_create(char *uri) +{ + private_vici_dispatcher_t *this; + + INIT(this, + .public = { + .manage_command = _manage_command, + .manage_event = _manage_event, + .raise_event = _raise_event, + .destroy = _destroy, + }, + .cmds = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1), + .events = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .cond = condvar_create(CONDVAR_TYPE_DEFAULT), + ); + + this->socket = vici_socket_create(uri, inbound, connect_, disconnect, this); + if (!this->socket) + { + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_dispatcher.h b/src/libcharon/plugins/vici/vici_dispatcher.h new file mode 100644 index 000000000..2297a80bd --- /dev/null +++ b/src/libcharon/plugins/vici/vici_dispatcher.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_dispatcher vici_dispatcher + * @{ @ingroup vici + */ + +#ifndef VICI_DISPATCHER_H_ +#define VICI_DISPATCHER_H_ + +#include "vici_message.h" + +typedef struct vici_dispatcher_t vici_dispatcher_t; +typedef enum vici_operation_t vici_operation_t; + +/** + * Default socket URI of vici service + */ +#ifdef WIN32 +# define VICI_DEFAULT_URI "tcp://127.0.0.1:4502" +#else +# define VICI_DEFAULT_URI "unix://" IPSEC_PIDDIR "/charon.vici" +#endif + +/** + * Kind of vici operation + */ +enum vici_operation_t { + /** a named request message */ + VICI_CMD_REQUEST, + /** an unnamed response message to a request */ + VICI_CMD_RESPONSE, + /** unnamed response if requested command is unknown */ + VICI_CMD_UNKNOWN, + /** a named event registration request */ + VICI_EVENT_REGISTER, + /** a named event unregistration request */ + VICI_EVENT_UNREGISTER, + /** unnamed response for successful event (un-)registration */ + VICI_EVENT_CONFIRM, + /** unnamed response if event (un-)registration failed */ + VICI_EVENT_UNKNOWN, + /** a named event message */ + VICI_EVENT, +}; + +/** + * Vici command callback function + * + * @param user user data, as supplied during registration + * @param name name of the command it has been registered under + * @param id client connection identifier + * @param request request message data + * @return response message + */ +typedef vici_message_t* (*vici_command_cb_t)(void *user, char *name, u_int id, + vici_message_t *request); + +/** + * Vici command dispatcher. + */ +struct vici_dispatcher_t { + + /** + * Register/Unregister a callback invoked for a specific command request. + * + * @param name name of the command + * @param cb callback function to register, NULL to unregister + * @param user user data to pass to callback + */ + void (*manage_command)(vici_dispatcher_t *this, char *name, + vici_command_cb_t cb, void *user); + + /** + * Register/Unregister an event type to send. + * + * The dispatcher internally manages event subscriptions. Clients registered + * for an event will receive such messages when the event is raised. + * + * @param name event name to manager + * @param reg TRUE to register, FALSE to unregister + */ + void (*manage_event)(vici_dispatcher_t *this, char *name, bool reg); + + /** + * Raise an event to a specific or all clients registered to that event. + * + * @param name event name to raise + * @param id client connection ID, 0 for all + * @param message event message to send, gets destroyed + */ + void (*raise_event)(vici_dispatcher_t *this, char *name, u_int id, + vici_message_t *message); + + /** + * Destroy a vici_dispatcher_t. + */ + void (*destroy)(vici_dispatcher_t *this); +}; + +/** + * Create a vici_dispatcher instance. + * + * @param uri uri for listening stream service + * @return dispatcher instance + */ +vici_dispatcher_t *vici_dispatcher_create(char *uri); + +#endif /** VICI_DISPATCHER_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_logger.c b/src/libcharon/plugins/vici/vici_logger.c new file mode 100644 index 000000000..cffd65bad --- /dev/null +++ b/src/libcharon/plugins/vici/vici_logger.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_logger.h" +#include "vici_builder.h" + +#include <daemon.h> +#include <threading/mutex.h> + +typedef struct private_vici_logger_t private_vici_logger_t; + +/** + * Private data of an vici_logger_t object. + */ +struct private_vici_logger_t { + + /** + * Public vici_logger_t interface. + */ + vici_logger_t public; + + /** + * Dispatcher + */ + vici_dispatcher_t *dispatcher; + + /** + * Recursiveness avoidance counter + */ + int recursive; + + /** + * Mutex to synchronize logging + */ + mutex_t *mutex; +}; + +METHOD(logger_t, log_, void, + private_vici_logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t* ike_sa, const char *msg) +{ + this->mutex->lock(this->mutex); + + /* avoid recursive invocations by the vici subsystem */ + if (this->recursive++ == 0) + { + vici_message_t *message; + vici_builder_t *builder; + + builder = vici_builder_create(); + builder->add_kv(builder, "group", "%N", debug_names, group); + builder->add_kv(builder, "level", "%d", level); + builder->add_kv(builder, "thread", "%d", thread); + if (ike_sa) + { + builder->add_kv(builder, "ikesa-name", "%s", + ike_sa->get_name(ike_sa)); + builder->add_kv(builder, "ikesa-uniqueid", "%u", + ike_sa->get_unique_id(ike_sa)); + } + builder->add_kv(builder, "msg", "%s", msg); + + message = builder->finalize(builder); + if (message) + { + this->dispatcher->raise_event(this->dispatcher, "log", 0, message); + } + } + this->recursive--; + + this->mutex->unlock(this->mutex); +} + +METHOD(logger_t, get_level, level_t, + private_vici_logger_t *this, debug_t group) +{ + return LEVEL_CTRL; +} + +/** + * (Un-)register dispatcher functions/events + */ +static void manage_commands(private_vici_logger_t *this, bool reg) +{ + this->dispatcher->manage_event(this->dispatcher, "log", reg); +} + +METHOD(vici_logger_t, destroy, void, + private_vici_logger_t *this) +{ + manage_commands(this, FALSE); + this->mutex->destroy(this->mutex); + free(this); +} + +/** + * See header + */ +vici_logger_t *vici_logger_create(vici_dispatcher_t *dispatcher) +{ + private_vici_logger_t *this; + + INIT(this, + .public = { + .logger = { + .log = _log_, + .get_level = _get_level, + }, + .destroy = _destroy, + }, + .dispatcher = dispatcher, + .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), + ); + + manage_commands(this, TRUE); + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_logger.h b/src/libcharon/plugins/vici/vici_logger.h new file mode 100644 index 000000000..7be1d60d4 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_logger.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_logger vici_logger + * @{ @ingroup vici + */ + +#ifndef VICI_LOGGER_H_ +#define VICI_LOGGER_H_ + +#include "vici_dispatcher.h" + +#include <bus/listeners/logger.h> + +typedef struct vici_logger_t vici_logger_t; + +/** + * Generic debugging logger over vici. + */ +struct vici_logger_t { + + /** + * Implements logger interface. + */ + logger_t logger; + + /** + * Destroy a vici_logger_t. + */ + void (*destroy)(vici_logger_t *this); +}; + +/** + * Create a vici_logger instance. + * + * @param dispatcher dispatcher to receive requests from + * @return loggerential backend + */ +vici_logger_t *vici_logger_create(vici_dispatcher_t *dispatcher); + +#endif /** VICI_LOGGER_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_message.c b/src/libcharon/plugins/vici/vici_message.c new file mode 100644 index 000000000..dcc175f67 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_message.c @@ -0,0 +1,727 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_message.h" +#include "vici_builder.h" + +#include <bio/bio_reader.h> +#include <bio/bio_writer.h> + +#include <errno.h> + +typedef struct private_vici_message_t private_vici_message_t; + +/** + * Private data of an vici_message_t object. + */ +struct private_vici_message_t { + + /** + * Public vici_message_t interface. + */ + vici_message_t public; + + /** + * Message encoding + */ + chunk_t encoding; + + /** + * Free encoding during destruction? + */ + bool cleanup; + + /** + * Allocated strings we maintain for get_str() + */ + linked_list_t *strings; +}; + +ENUM(vici_type_names, VICI_START, VICI_END, + "start", + "section-start", + "section-end", + "key-value", + "list-start", + "list-item", + "list-end", + "end" +); + +/** + * See header. + */ +bool vici_stringify(chunk_t chunk, char *buf, size_t size) +{ + if (!chunk_printable(chunk, NULL, 0)) + { + return FALSE; + } + snprintf(buf, size, "%.*s", (int)chunk.len, chunk.ptr); + return TRUE; +} + +/** + * See header. + */ +bool vici_verify_type(vici_type_t type, u_int section, bool list) +{ + if (list) + { + if (type != VICI_LIST_END && type != VICI_LIST_ITEM) + { + DBG1(DBG_ENC, "'%N' within list", vici_type_names, type); + return FALSE; + } + } + else + { + if (type == VICI_LIST_ITEM || type == VICI_LIST_END) + { + DBG1(DBG_ENC, "'%N' outside list", vici_type_names, type); + return FALSE; + } + } + if (type == VICI_SECTION_END && section == 0) + { + DBG1(DBG_ENC, "'%N' outside of section", vici_type_names, type); + return FALSE; + } + if (type == VICI_END) + { + if (section) + { + DBG1(DBG_ENC, "'%N' within section", vici_type_names, type); + return FALSE; + } + if (list) + { + DBG1(DBG_ENC, "'%N' within list", vici_type_names, type); + return FALSE; + } + } + return TRUE; +} + +/** + * Enumerator parsing message + */ +typedef struct { + /* implements enumerator */ + enumerator_t public; + /** reader to parse from */ + bio_reader_t *reader; + /** section nesting level */ + int section; + /** currently parsing list? */ + bool list; + /** string currently enumerating */ + char name[257]; +} parse_enumerator_t; + +METHOD(enumerator_t, parse_enumerate, bool, + parse_enumerator_t *this, vici_type_t *out, char **name, chunk_t *value) +{ + u_int8_t type; + chunk_t data; + + if (!this->reader->remaining(this->reader) || + !this->reader->read_uint8(this->reader, &type)) + { + *out = VICI_END; + return TRUE; + } + if (!vici_verify_type(type, this->section, this->list)) + { + return FALSE; + } + + switch (type) + { + case VICI_SECTION_START: + if (!this->reader->read_data8(this->reader, &data) || + !vici_stringify(data, this->name, sizeof(this->name))) + { + DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type); + return FALSE; + } + *name = this->name; + this->section++; + break; + case VICI_SECTION_END: + this->section--; + break; + case VICI_KEY_VALUE: + if (!this->reader->read_data8(this->reader, &data) || + !vici_stringify(data, this->name, sizeof(this->name)) || + !this->reader->read_data16(this->reader, value)) + { + DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type); + return FALSE; + } + *name = this->name; + break; + case VICI_LIST_START: + if (!this->reader->read_data8(this->reader, &data) || + !vici_stringify(data, this->name, sizeof(this->name))) + { + DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type); + return FALSE; + } + *name = this->name; + this->list = TRUE; + break; + case VICI_LIST_ITEM: + this->reader->read_data16(this->reader, value); + break; + case VICI_LIST_END: + this->list = FALSE; + break; + case VICI_END: + return TRUE; + default: + DBG1(DBG_ENC, "unknown encoding type: %u", type); + return FALSE; + } + + *out = type; + + return TRUE; +} + +METHOD(enumerator_t, parse_destroy, void, + parse_enumerator_t *this) +{ + this->reader->destroy(this->reader); + free(this); +} + +METHOD(vici_message_t, create_enumerator, enumerator_t*, + private_vici_message_t *this) +{ + parse_enumerator_t *enumerator; + + INIT(enumerator, + .public = { + .enumerate = (void*)_parse_enumerate, + .destroy = _parse_destroy, + }, + .reader = bio_reader_create(this->encoding), + ); + + return &enumerator->public; +} + +/** + * Find a value for given vararg key + */ +static bool find_value(private_vici_message_t *this, chunk_t *value, + char *fmt, va_list args) +{ + enumerator_t *enumerator; + char buf[128], *name, *key, *dot, *next; + int section = 0, keysection = 0; + bool found = FALSE; + chunk_t current; + vici_type_t type; + + vsnprintf(buf, sizeof(buf), fmt, args); + next = buf; + + enumerator = create_enumerator(this); + + /* descent into section */ + while (TRUE) + { + dot = strchr(next, '.'); + if (!dot) + { + key = next; + break; + } + *dot = '\0'; + key = next; + next = dot + 1; + keysection++; + + while (enumerator->enumerate(enumerator, &type, &name, ¤t)) + { + switch (type) + { + case VICI_SECTION_START: + section++; + if (section == keysection && streq(name, key)) + { + break; + } + continue; + case VICI_SECTION_END: + section--; + continue; + case VICI_END: + break; + default: + continue; + } + break; + } + } + + /* find key/value in current section */ + while (enumerator->enumerate(enumerator, &type, &name, ¤t)) + { + switch (type) + { + case VICI_KEY_VALUE: + if (section == keysection && streq(key, name)) + { + *value = current; + found = TRUE; + break; + } + continue; + case VICI_SECTION_START: + section++; + continue; + case VICI_SECTION_END: + section--; + continue; + case VICI_END: + break; + default: + continue; + } + break; + } + + enumerator->destroy(enumerator); + + return found; +} + +METHOD(vici_message_t, vget_str, char*, + private_vici_message_t *this, char *def, char *fmt, va_list args) +{ + chunk_t value; + bool found; + char *str; + + found = find_value(this, &value, fmt, args); + if (found) + { + if (chunk_printable(value, NULL, 0)) + { + str = strndup(value.ptr, value.len); + /* keep a reference to string, so caller doesn't have to care */ + this->strings->insert_last(this->strings, str); + return str; + } + } + return def; +} + +METHOD(vici_message_t, get_str, char*, + private_vici_message_t *this, char *def, char *fmt, ...) +{ + va_list args; + char *str; + + va_start(args, fmt); + str = vget_str(this, def, fmt, args); + va_end(args); + return str; +} + +METHOD(vici_message_t, vget_int, int, + private_vici_message_t *this, int def, char *fmt, va_list args) +{ + chunk_t value; + bool found; + char buf[32], *pos; + int ret; + + found = find_value(this, &value, fmt, args); + if (found) + { + if (chunk_printable(value, NULL, 0)) + { + snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr); + errno = 0; + ret = strtol(buf, &pos, 0); + if (errno == 0 && pos == buf + strlen(buf)) + { + return ret; + } + } + } + return def; +} + +METHOD(vici_message_t, get_int, int, + private_vici_message_t *this, int def, char *fmt, ...) +{ + va_list args; + int val; + + va_start(args, fmt); + val = vget_int(this, def, fmt, args); + va_end(args); + return val; +} + +METHOD(vici_message_t, vget_value, chunk_t, + private_vici_message_t *this, chunk_t def, char *fmt, va_list args) +{ + chunk_t value; + bool found; + + found = find_value(this, &value, fmt, args); + if (found) + { + return value; + } + return def; +} + +METHOD(vici_message_t, get_value, chunk_t, + private_vici_message_t *this, chunk_t def, char *fmt, ...) +{ + va_list args; + chunk_t value; + + va_start(args, fmt); + value = vget_value(this, def, fmt, args); + va_end(args); + return value; +} + +METHOD(vici_message_t, get_encoding, chunk_t, + private_vici_message_t *this) +{ + return this->encoding; +} + +/** + * Private parse context data + */ +struct vici_parse_context_t { + /** current section nesting level */ + int level; + /** parse enumerator */ + enumerator_t *e; +}; + +METHOD(vici_message_t, parse, bool, + private_vici_message_t *this, vici_parse_context_t *ctx, + vici_section_cb_t section, vici_value_cb_t kv, vici_value_cb_t li, + void *user) +{ + vici_parse_context_t root = {}; + char *name, *list = NULL; + vici_type_t type; + chunk_t value; + int base; + bool ok = TRUE; + + if (!ctx) + { + ctx = &root; + root.e = create_enumerator(this); + } + + base = ctx->level; + + while (ok) + { + ok = ctx->e->enumerate(ctx->e, &type, &name, &value); + if (ok) + { + switch (type) + { + case VICI_START: + /* should never occur */ + continue; + case VICI_KEY_VALUE: + if (ctx->level == base && kv) + { + name = strdup(name); + this->strings->insert_last(this->strings, name); + ok = kv(user, &this->public, name, value); + } + continue; + case VICI_LIST_START: + if (ctx->level == base) + { + list = strdup(name); + this->strings->insert_last(this->strings, list); + } + continue; + case VICI_LIST_ITEM: + if (list && li) + { + name = strdup(name); + this->strings->insert_last(this->strings, name); + ok = li(user, &this->public, list, value); + } + continue; + case VICI_LIST_END: + if (ctx->level == base) + { + list = NULL; + } + continue; + case VICI_SECTION_START: + if (ctx->level++ == base && section) + { + name = strdup(name); + this->strings->insert_last(this->strings, name); + ok = section(user, &this->public, ctx, name); + } + continue; + case VICI_SECTION_END: + if (ctx->level-- == base) + { + break; + } + continue; + case VICI_END: + break; + } + } + break; + } + + if (ctx == &root) + { + root.e->destroy(root.e); + } + return ok; +} + +METHOD(vici_message_t, dump, bool, + private_vici_message_t *this, char *label, bool pretty, FILE *out) +{ + enumerator_t *enumerator; + int ident = 0, delta; + vici_type_t type, last_type = VICI_START; + char *name, *term, *sep, *separ, *assign; + chunk_t value; + + /* pretty print uses indentation on multiple lines */ + if (pretty) + { + delta = 2; + term = "\n"; + separ = ""; + assign = " = "; + } + else + { + delta = 0; + term = ""; + separ = " "; + assign = "="; + } + + fprintf(out, "%s {%s", label, term); + ident += delta; + + enumerator = create_enumerator(this); + while (enumerator->enumerate(enumerator, &type, &name, &value)) + { + switch (type) + { + case VICI_START: + /* should never occur */ + break; + case VICI_SECTION_START: + sep = (last_type != VICI_SECTION_START && + last_type != VICI_START) ? separ : ""; + fprintf(out, "%*s%s%s {%s", ident, "", sep, name, term); + ident += delta; + break; + case VICI_SECTION_END: + ident -= delta; + fprintf(out, "%*s}%s", ident, "", term); + break; + case VICI_KEY_VALUE: + sep = (last_type != VICI_SECTION_START && + last_type != VICI_START) ? separ : ""; + if (chunk_printable(value, NULL, ' ')) + { + fprintf(out, "%*s%s%s%s%.*s%s", ident, "", sep, name, + assign, (int)value.len, value.ptr, term); + } + else + { + fprintf(out, "%*s%s%s%s0x%+#B%s", ident, "", sep, name, + assign, &value, term); + } + break; + case VICI_LIST_START: + sep = (last_type != VICI_SECTION_START && + last_type != VICI_START) ? separ : ""; + fprintf(out, "%*s%s%s%s[%s", ident, "", sep, name, assign, term); + ident += delta; + break; + case VICI_LIST_END: + ident -= delta; + fprintf(out, "%*s]%s", ident, "", term); + break; + case VICI_LIST_ITEM: + sep = (last_type != VICI_LIST_START) ? separ : ""; + if (chunk_printable(value, NULL, ' ')) + { + fprintf(out, "%*s%s%.*s%s", ident, "", sep, + (int)value.len, value.ptr, term); + } + else + { + fprintf(out, "%*s%s0x%+#B%s", ident, "", sep, + &value, term); + } + break; + case VICI_END: + fprintf(out, "}\n"); + enumerator->destroy(enumerator); + return TRUE; + } + last_type = type; + } + enumerator->destroy(enumerator); + return FALSE; +} + +METHOD(vici_message_t, destroy, void, + private_vici_message_t *this) +{ + if (this->cleanup) + { + chunk_clear(&this->encoding); + } + this->strings->destroy_function(this->strings, free); + free(this); +} + +/** + * See header + */ +vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup) +{ + private_vici_message_t *this; + + INIT(this, + .public = { + .create_enumerator = _create_enumerator, + .get_str = _get_str, + .vget_str = _vget_str, + .get_int = _get_int, + .vget_int = _vget_int, + .get_value = _get_value, + .vget_value = _vget_value, + .get_encoding = _get_encoding, + .parse = _parse, + .dump = _dump, + .destroy = _destroy, + }, + .strings = linked_list_create(), + .encoding = data, + .cleanup = cleanup, + ); + + return &this->public; +} + +/** + * See header + */ +vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator) +{ + vici_builder_t *builder; + vici_type_t type; + char *name; + chunk_t value; + + builder = vici_builder_create(); + while (enumerator->enumerate(enumerator, &type, &name, &value)) + { + switch (type) + { + case VICI_SECTION_START: + case VICI_LIST_START: + builder->add(builder, type, name); + continue; + case VICI_KEY_VALUE: + builder->add(builder, type, name, value); + continue; + case VICI_LIST_ITEM: + builder->add(builder, type, value); + continue; + case VICI_SECTION_END: + case VICI_LIST_END: + default: + builder->add(builder, type); + continue; + case VICI_END: + break; + } + break; + } + enumerator->destroy(enumerator); + + return builder->finalize(builder); +} + +/** + * See header + */ +vici_message_t *vici_message_create_from_args(vici_type_t type, ...) +{ + vici_builder_t *builder; + va_list args; + char *name; + chunk_t value; + + builder = vici_builder_create(); + va_start(args, type); + while (type != VICI_END) + { + switch (type) + { + case VICI_LIST_START: + case VICI_SECTION_START: + name = va_arg(args, char*); + builder->add(builder, type, name); + break; + case VICI_KEY_VALUE: + name = va_arg(args, char*); + value = va_arg(args, chunk_t); + builder->add(builder, type, name, value); + break; + case VICI_LIST_ITEM: + value = va_arg(args, chunk_t); + builder->add(builder, type, value); + break; + case VICI_SECTION_END: + case VICI_LIST_END: + default: + builder->add(builder, type); + break; + } + type = va_arg(args, vici_type_t); + } + va_end(args); + return builder->finalize(builder); +} diff --git a/src/libcharon/plugins/vici/vici_message.h b/src/libcharon/plugins/vici/vici_message.h new file mode 100644 index 000000000..1a89cf829 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_message.h @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_message vici_message + * @{ @ingroup vici_dispatcher + */ + +#ifndef VICI_MESSAGE_H_ +#define VICI_MESSAGE_H_ + +#include <library.h> + +typedef struct vici_message_t vici_message_t; +typedef struct vici_parse_context_t vici_parse_context_t; +typedef enum vici_type_t vici_type_t; + +/** + * Vici message encoding types + */ +enum vici_type_t { + /** never used in an argument list, needed by dump as initial value */ + VICI_START = 0, + + /** begin of new section, argument is section name as char* */ + VICI_SECTION_START = 1, + /** end of current section, no arguments */ + VICI_SECTION_END = 2, + /** key/value, arguments are key as char*, value as chunk_t */ + VICI_KEY_VALUE = 3, + /** list start, argument is list name as char* */ + VICI_LIST_START = 4, + /** list item, argument is item value as chunk_t */ + VICI_LIST_ITEM = 5, + /** end of list, no arguments */ + VICI_LIST_END = 6, + + /** end of argument list, no arguments (never encoded) */ + VICI_END = 7 +}; + +/** + * Callback function for key/value and list items, invoked by parse(). + * + * @param user user data, as passed to parse() + * @param message message currently parsing + * @param name name of key or list + * @param value parsed value + * @return TRUE if parsed successfully + */ +typedef bool (*vici_value_cb_t)(void *user, vici_message_t *message, + char *name, chunk_t value); + +/** + * Callback function for sections, invoked by parse(). + * + * @param user user data, as passed to parse() + * @param message message currently parsing + * @param ctx parse context, to pass to recursive parse() invocations. + * @param name name of the section + * @return TRUE if parsed successfully + */ +typedef bool (*vici_section_cb_t)(void *user, vici_message_t *message, + vici_parse_context_t *ctx, char *name); + +/** + * Names for vici encoding types + */ +extern enum_name_t *vici_type_names; + +/** + * Vici message representation, encoding/decoding routines. + */ +struct vici_message_t { + + /** + * Create an enumerator over message contents. + * + * The enumerator takes a fixed list of arguments, but depending on the + * type may set not all of them. It returns VICI_END as last argument + * to indicate the message end, and returns FALSE if parsing the message + * failed. + * + * @return enumerator over (vici_type_t, char*, chunk_t) + */ + enumerator_t* (*create_enumerator)(vici_message_t *this); + + /** + * Get the value of a key/value pair as a string. + * + * @param def default value if not found + * @param fmt printf style format string for key, with sections + * @param ... arguments to fmt string + * @return string + */ + char* (*get_str)(vici_message_t *this, char *def, char *fmt, ...); + + /** + * Get the value of a key/value pair as a string, va_list variant. + * + * @param def default value if not found + * @param fmt printf style format string for key, with sections + * @param args arguments to fmt string + * @return string + */ + char* (*vget_str)(vici_message_t *this, char *def, char *fmt, va_list args); + + /** + * Get the value of a key/value pair as integer. + * + * @param def default value if not found + * @param fmt printf style format string for key, with sections + * @param ... arguments to fmt string + * @return value + */ + int (*get_int)(vici_message_t *this, int def, char *fmt, ...); + + /** + * Get the value of a key/value pair as integer, va_list variant + * + * @param def default value if not found + * @param fmt printf style format string for key, with sections + * @param args arguments to fmt string + * @return value + */ + int (*vget_int)(vici_message_t *this, int def, char *fmt, va_list args); + + /** + * Get the raw value of a key/value pair. + * + * @param def default value if not found + * @param fmt printf style format string for key, with sections + * @param ... arguments to fmt string + * @return value + */ + chunk_t (*get_value)(vici_message_t *this, chunk_t def, char *fmt, ...); + + /** + * Get the raw value of a key/value pair, va_list variant. + * + * @param def default value if not found + * @param fmt printf style format string for key, with sections + * @param args arguments to fmt string + * @return value + */ + chunk_t (*vget_value)(vici_message_t *this, chunk_t def, + char *fmt, va_list args); + + /** + * Get encoded message. + * + * @return message data, points to internal data + */ + chunk_t (*get_encoding)(vici_message_t *this); + + /** + * Parse a message using callback functions. + * + * Any of the callbacks may be NULL to skip this kind of item. Callbacks are + * invoked for the current section level only. To descent into sections, + * call parse() from within a section callback using the provided parse + * context. + * + * @param ctx parse context, NULL for root level + * @param section callback invoked for each section + * @param kv callback invoked for key/value pairs + * @param li callback invoked for list items + * @param user user data to pass to callbacks + * @return TRUE if parsed successfully + */ + bool (*parse)(vici_message_t *this, vici_parse_context_t *ctx, + vici_section_cb_t section, vici_value_cb_t kv, + vici_value_cb_t li, void *user); + + /** + * Dump a message text representation to a FILE stream. + * + * @param label label to print for message + * @param pretty use pretty print with indentation + * @param out FILE stream to dump to + * @return TRUE if message valid + */ + bool (*dump)(vici_message_t *this, char *label, bool pretty, FILE *out); + + /** + * Destroy a vici_message_t. + */ + void (*destroy)(vici_message_t *this); +}; + +/** + * Create a vici_message from encoded data. + * + * @param data message encoding + * @param cleanup TRUE to free data during + * @return message representation + */ +vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup); + +/** + * Create a vici_message from an enumerator. + * + * The enumerator uses the same signature as the enumerator returned + * by create_enumerator(), and gets destroyed by this function. It should + * return VICI_END to close the message, return FALSE to indicate a failure. + * + * @param enumerator enumerator over (vici_type_t, char*, chunk_t) + * @return message representation, NULL on error + */ +vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator); + +/** + * Create vici message from a variable argument list. + * + * @param type first type beginning message + * @param ... vici_type_t and args, terminated by VICI_END + * @return message representation, NULL on error + */ +vici_message_t *vici_message_create_from_args(vici_type_t type, ...); + +/** + * Check if a chunk has a printable string, and print it to buf. + * + * @param chunk chunk containing potential string + * @param buf buffer to write string to + * @param size size of buf + * @return TRUE if printable and string written to buf + */ +bool vici_stringify(chunk_t chunk, char *buf, size_t size); + +/** + * Verify the occurrence of a given type for given section/list nesting + */ +bool vici_verify_type(vici_type_t type, u_int section, bool list); + +#endif /** VICI_MESSAGE_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_plugin.c b/src/libcharon/plugins/vici/vici_plugin.c new file mode 100644 index 000000000..8881feca9 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_plugin.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_plugin.h" +#include "vici_dispatcher.h" +#include "vici_query.h" +#include "vici_control.h" +#include "vici_cred.h" +#include "vici_config.h" +#include "vici_attribute.h" +#include "vici_logger.h" + +#include <library.h> +#include <hydra.h> +#include <daemon.h> + +typedef struct private_vici_plugin_t private_vici_plugin_t; + +/** + * Private members of vici_plugin_t + */ +struct private_vici_plugin_t { + + /** + * public functions + */ + vici_plugin_t public; + + /** + * Dispatcher, creating socket + */ + vici_dispatcher_t *dispatcher; + + /** + * Query commands + */ + vici_query_t *query; + + /** + * Control commands + */ + vici_control_t *control; + + /** + * Credential backend + */ + vici_cred_t *cred; + + /** + * Configuration backend + */ + vici_config_t *config; + + /** + * IKE attribute backend + */ + vici_attribute_t *attrs; + + /** + * Generic debug logger + */ + vici_logger_t *logger; +}; + +METHOD(plugin_t, get_name, char*, + private_vici_plugin_t *this) +{ + return "vici"; +} + +/** + * Register vici plugin features + */ +static bool register_vici(private_vici_plugin_t *this, + plugin_feature_t *feature, bool reg, void *data) +{ + if (reg) + { + char *uri; + + uri = lib->settings->get_str(lib->settings, "%s.plugins.vici.socket", + VICI_DEFAULT_URI, lib->ns); + this->dispatcher = vici_dispatcher_create(uri); + if (this->dispatcher) + { + this->query = vici_query_create(this->dispatcher); + this->control = vici_control_create(this->dispatcher); + this->cred = vici_cred_create(this->dispatcher); + this->config = vici_config_create(this->dispatcher); + this->attrs = vici_attribute_create(this->dispatcher); + this->logger = vici_logger_create(this->dispatcher); + + charon->backends->add_backend(charon->backends, + &this->config->backend); + hydra->attributes->add_provider(hydra->attributes, + &this->attrs->provider); + charon->bus->add_logger(charon->bus, &this->logger->logger); + return TRUE; + } + return FALSE; + } + else + { + charon->bus->remove_logger(charon->bus, &this->logger->logger); + hydra->attributes->remove_provider(hydra->attributes, + &this->attrs->provider); + charon->backends->remove_backend(charon->backends, + &this->config->backend); + + this->logger->destroy(this->logger); + this->attrs->destroy(this->attrs); + this->config->destroy(this->config); + this->cred->destroy(this->cred); + this->control->destroy(this->control); + this->query->destroy(this->query); + this->dispatcher->destroy(this->dispatcher); + } + return TRUE; +} + +METHOD(plugin_t, get_features, int, + private_vici_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)register_vici, NULL), + PLUGIN_PROVIDE(CUSTOM, "vici"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_vici_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *vici_plugin_create() +{ + private_vici_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .reload = (void*)return_false, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/vici/vici_plugin.h b/src/libcharon/plugins/vici/vici_plugin.h new file mode 100644 index 000000000..b4c380200 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici vici + * @ingroup cplugins + * + * @defgroup vici_plugin vici_plugin + * @{ @ingroup vici + */ + +#ifndef VICI_PLUGIN_H_ +#define VICI_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct vici_plugin_t vici_plugin_t; + +/** + * vici plugin, the "Versatile IKE Control Interface" interface. + */ +struct vici_plugin_t { + + /** + * Implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** VICI_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c new file mode 100644 index 000000000..54833abde --- /dev/null +++ b/src/libcharon/plugins/vici/vici_query.c @@ -0,0 +1,1039 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_query.h" +#include "vici_builder.h" + +#include <inttypes.h> +#include <time.h> +#ifndef WIN32 +#include <sys/utsname.h> +#endif +#ifdef HAVE_MALLINFO +#include <malloc.h> +#endif + +#include <daemon.h> + +typedef struct private_vici_query_t private_vici_query_t; + +/** + * Private data of an vici_query_t object. + */ +struct private_vici_query_t { + + /** + * Public vici_query_t interface. + */ + vici_query_t public; + + /** + * Dispatcher + */ + vici_dispatcher_t *dispatcher; + + /** + * Daemon startup timestamp + */ + time_t uptime; +}; + +/** + * List details of a CHILD_SA + */ +static void list_child(private_vici_query_t *this, vici_builder_t *b, + child_sa_t *child, time_t now) +{ + time_t t; + u_int64_t bytes, packets; + u_int16_t alg, ks; + proposal_t *proposal; + enumerator_t *enumerator; + traffic_selector_t *ts; + + b->add_kv(b, "reqid", "%u", child->get_reqid(child)); + b->add_kv(b, "state", "%N", child_sa_state_names, child->get_state(child)); + b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child)); + if (child->get_state(child) == CHILD_INSTALLED || + child->get_state(child) == CHILD_REKEYING) + { + b->add_kv(b, "protocol", "%N", protocol_id_names, + child->get_protocol(child)); + if (child->has_encap(child)) + { + b->add_kv(b, "encap", "yes"); + } + b->add_kv(b, "spi-in", "%.8x", ntohl(child->get_spi(child, TRUE))); + b->add_kv(b, "spi-out", "%.8x", ntohl(child->get_spi(child, FALSE))); + + if (child->get_ipcomp(child) != IPCOMP_NONE) + { + b->add_kv(b, "cpi-in", "%.4x", ntohs(child->get_cpi(child, TRUE))); + b->add_kv(b, "cpi-out", "%.4x", ntohs(child->get_cpi(child, FALSE))); + } + proposal = child->get_proposal(child); + if (proposal) + { + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, + &alg, &ks) && alg != ENCR_UNDEFINED) + { + b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg); + if (ks) + { + b->add_kv(b, "encr-keysize", "%u", ks); + } + } + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &alg, &ks) && alg != ENCR_UNDEFINED) + { + b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg); + if (ks) + { + b->add_kv(b, "integ-keysize", "%u", ks); + } + } + if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, + &alg, NULL)) + { + b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg); + } + if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + &alg, NULL)) + { + b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg); + } + if (proposal->get_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, + &alg, NULL) && alg == EXT_SEQ_NUMBERS) + { + b->add_kv(b, "esn", "1"); + } + } + + child->get_usestats(child, TRUE, &t, &bytes, &packets); + b->add_kv(b, "bytes-in", "%" PRIu64, bytes); + b->add_kv(b, "packets-in", "%" PRIu64, packets); + if (t) + { + b->add_kv(b, "use-in", "%"PRIu64, (u_int64_t)(now - t)); + } + + child->get_usestats(child, FALSE, &t, &bytes, &packets); + b->add_kv(b, "bytes-out", "%"PRIu64, bytes); + b->add_kv(b, "packets-out", "%"PRIu64, packets); + if (t) + { + b->add_kv(b, "use-out", "%"PRIu64, (u_int64_t)(now - t)); + } + + t = child->get_lifetime(child, FALSE); + if (t) + { + b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now)); + } + t = child->get_lifetime(child, TRUE); + if (t) + { + b->add_kv(b, "life-time", "%"PRId64, (int64_t)(t - now)); + } + t = child->get_installtime(child); + b->add_kv(b, "install-time", "%"PRId64, (int64_t)(now - t)); + } + + b->begin_list(b, "local-ts"); + enumerator = child->create_ts_enumerator(child, TRUE); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + b->end_list(b /* local-ts */); + + b->begin_list(b, "remote-ts"); + enumerator = child->create_ts_enumerator(child, FALSE); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + b->end_list(b /* remote-ts */); +} + +/** + * List tasks in a specific queue + */ +static void list_task_queue(private_vici_query_t *this, vici_builder_t *b, + ike_sa_t *ike_sa, task_queue_t q, char *name) +{ + enumerator_t *enumerator; + bool has = FALSE; + task_t *task; + + enumerator = ike_sa->create_task_enumerator(ike_sa, q); + while (enumerator->enumerate(enumerator, &task)) + { + if (!has) + { + b->begin_list(b, name); + has = TRUE; + } + b->add_li(b, "%N", task_type_names, task->get_type(task)); + } + enumerator->destroy(enumerator); + if (has) + { + b->end_list(b); + } +} + +/** + * List details of an IKE_SA + */ +static void list_ike(private_vici_query_t *this, vici_builder_t *b, + ike_sa_t *ike_sa, time_t now) +{ + time_t t; + ike_sa_id_t *id; + identification_t *eap; + proposal_t *proposal; + u_int16_t alg, ks; + + b->add_kv(b, "uniqueid", "%u", ike_sa->get_unique_id(ike_sa)); + b->add_kv(b, "version", "%u", ike_sa->get_version(ike_sa)); + b->add_kv(b, "state", "%N", ike_sa_state_names, ike_sa->get_state(ike_sa)); + + b->add_kv(b, "local-host", "%H", ike_sa->get_my_host(ike_sa)); + b->add_kv(b, "local-id", "%Y", ike_sa->get_my_id(ike_sa)); + + b->add_kv(b, "remote-host", "%H", ike_sa->get_other_host(ike_sa)); + b->add_kv(b, "remote-id", "%Y", ike_sa->get_other_id(ike_sa)); + + eap = ike_sa->get_other_eap_id(ike_sa); + + if (!eap->equals(eap, ike_sa->get_other_id(ike_sa))) + { + if (ike_sa->get_version(ike_sa) == IKEV1) + { + b->add_kv(b, "remote-xauth-id", "%Y", eap); + } + else + { + b->add_kv(b, "remote-eap-id", "%Y", eap); + } + } + + id = ike_sa->get_id(ike_sa); + if (id->is_initiator(id)) + { + b->add_kv(b, "initiator", "yes"); + } + b->add_kv(b, "initiator-spi", "%.16"PRIx64, id->get_initiator_spi(id)); + b->add_kv(b, "responder-spi", "%.16"PRIx64, id->get_responder_spi(id)); + + proposal = ike_sa->get_proposal(ike_sa); + if (proposal) + { + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &ks)) + { + b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg); + if (ks) + { + b->add_kv(b, "encr-keysize", "%u", ks); + } + } + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, &ks)) + { + b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg); + if (ks) + { + b->add_kv(b, "integ-keysize", "%u", ks); + } + } + if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) + { + b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg); + } + if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &alg, NULL)) + { + b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg); + } + } + + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED) + { + t = ike_sa->get_statistic(ike_sa, STAT_ESTABLISHED); + b->add_kv(b, "established", "%"PRId64, (int64_t)(now - t)); + t = ike_sa->get_statistic(ike_sa, STAT_REKEY); + if (t) + { + b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now)); + } + t = ike_sa->get_statistic(ike_sa, STAT_REAUTH); + if (t) + { + b->add_kv(b, "reauth-time", "%"PRId64, (int64_t)(t - now)); + } + } + + list_task_queue(this, b, ike_sa, TASK_QUEUE_QUEUED, "tasks-queued"); + list_task_queue(this, b, ike_sa, TASK_QUEUE_ACTIVE, "tasks-active"); + list_task_queue(this, b, ike_sa, TASK_QUEUE_PASSIVE, "tasks-passive"); +} + +CALLBACK(list_sas, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + vici_builder_t *b; + enumerator_t *isas, *csas; + ike_sa_t *ike_sa; + child_sa_t *child_sa; + time_t now; + char *ike; + u_int ike_id; + bool bl; + + bl = request->get_str(request, NULL, "noblock") == NULL; + ike = request->get_str(request, NULL, "ike"); + ike_id = request->get_int(request, 0, "ike-id"); + + isas = charon->controller->create_ike_sa_enumerator(charon->controller, bl); + while (isas->enumerate(isas, &ike_sa)) + { + if (ike && !streq(ike, ike_sa->get_name(ike_sa))) + { + continue; + } + if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa)) + { + continue; + } + + now = time_monotonic(NULL); + + b = vici_builder_create(); + b->begin_section(b, ike_sa->get_name(ike_sa)); + + list_ike(this, b, ike_sa, now); + + b->begin_section(b, "child-sas"); + csas = ike_sa->create_child_sa_enumerator(ike_sa); + while (csas->enumerate(csas, &child_sa)) + { + b->begin_section(b, child_sa->get_name(child_sa)); + list_child(this, b, child_sa, now); + b->end_section(b); + } + csas->destroy(csas); + b->end_section(b /* child-sas */ ); + + b->end_section(b); + + this->dispatcher->raise_event(this->dispatcher, "list-sa", id, + b->finalize(b)); + } + isas->destroy(isas); + + b = vici_builder_create(); + return b->finalize(b); +} + +/** + * Raise a list-policy event for given CHILD_SA + */ +static void raise_policy(private_vici_query_t *this, u_int id, child_sa_t *child) +{ + enumerator_t *enumerator; + traffic_selector_t *ts; + vici_builder_t *b; + + b = vici_builder_create(); + b->begin_section(b, child->get_name(child)); + + b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child)); + + b->begin_list(b, "local-ts"); + enumerator = child->create_ts_enumerator(child, TRUE); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + b->end_list(b /* local-ts */); + + b->begin_list(b, "remote-ts"); + enumerator = child->create_ts_enumerator(child, FALSE); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + b->end_list(b /* remote-ts */); + + b->end_section(b); + + this->dispatcher->raise_event(this->dispatcher, "list-policy", id, + b->finalize(b)); +} + +/** + * Raise a list-policy event for given CHILD_SA config + */ +static void raise_policy_cfg(private_vici_query_t *this, u_int id, + child_cfg_t *cfg) +{ + enumerator_t *enumerator; + linked_list_t *list; + traffic_selector_t *ts; + vici_builder_t *b; + + b = vici_builder_create(); + b->begin_section(b, cfg->get_name(cfg)); + + b->add_kv(b, "mode", "%N", ipsec_mode_names, cfg->get_mode(cfg)); + + b->begin_list(b, "local-ts"); + list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + b->end_list(b /* local-ts */); + + b->begin_list(b, "remote-ts"); + list = cfg->get_traffic_selectors(cfg, FALSE, NULL, NULL); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + b->end_list(b /* remote-ts */); + + b->end_section(b); + + this->dispatcher->raise_event(this->dispatcher, "list-policy", id, + b->finalize(b)); +} + +CALLBACK(list_policies, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + enumerator_t *enumerator; + vici_builder_t *b; + child_sa_t *child_sa; + child_cfg_t *child_cfg; + bool drop, pass, trap; + char *child; + + drop = request->get_str(request, NULL, "drop") != NULL; + pass = request->get_str(request, NULL, "pass") != NULL; + trap = request->get_str(request, NULL, "trap") != NULL; + child = request->get_str(request, NULL, "child"); + + if (trap) + { + enumerator = charon->traps->create_enumerator(charon->traps); + while (enumerator->enumerate(enumerator, NULL, &child_sa)) + { + if (child && !streq(child, child_sa->get_name(child_sa))) + { + continue; + } + raise_policy(this, id, child_sa); + } + enumerator->destroy(enumerator); + } + + if (drop || pass) + { + enumerator = charon->shunts->create_enumerator(charon->shunts); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + if (child && !streq(child, child_cfg->get_name(child_cfg))) + { + continue; + } + switch (child_cfg->get_mode(child_cfg)) + { + case MODE_DROP: + if (drop) + { + raise_policy_cfg(this, id, child_cfg); + } + break; + case MODE_PASS: + if (pass) + { + raise_policy_cfg(this, id, child_cfg); + } + break; + default: + break; + } + } + enumerator->destroy(enumerator); + } + + b = vici_builder_create(); + return b->finalize(b); +} + +/** + * Build sections for auth configs, local or remote + */ +static void build_auth_cfgs(peer_cfg_t *peer_cfg, bool local, vici_builder_t *b) +{ + enumerator_t *enumerator, *rules; + auth_rule_t rule; + auth_cfg_t *auth; + union { + uintptr_t u; + identification_t *id; + certificate_t *cert; + char *str; + } v; + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); + while (enumerator->enumerate(enumerator, &auth)) + { + b->begin_section(b, local ? "local" : "remote"); + + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &v)) + { + switch (rule) + { + case AUTH_RULE_AUTH_CLASS: + b->add_kv(b, "class", "%N", auth_class_names, v.u); + break; + case AUTH_RULE_EAP_TYPE: + b->add_kv(b, "eap-type", "%N", eap_type_names, v.u); + break; + case AUTH_RULE_EAP_VENDOR: + b->add_kv(b, "eap-vendor", "%u", v.u); + break; + case AUTH_RULE_XAUTH_BACKEND: + b->add_kv(b, "xauth", "%s", v.str); + break; + case AUTH_RULE_CRL_VALIDATION: + b->add_kv(b, "revocation", "%N", cert_validation_names, v.u); + break; + case AUTH_RULE_IDENTITY: + b->add_kv(b, "id", "%Y", v.id); + break; + case AUTH_RULE_AAA_IDENTITY: + b->add_kv(b, "aaa_id", "%Y", v.id); + break; + case AUTH_RULE_EAP_IDENTITY: + b->add_kv(b, "eap_id", "%Y", v.id); + break; + case AUTH_RULE_XAUTH_IDENTITY: + b->add_kv(b, "xauth_id", "%Y", v.id); + break; + default: + break; + } + } + rules->destroy(rules); + + b->begin_list(b, "groups"); + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &v)) + { + if (rule == AUTH_RULE_GROUP) + { + b->add_li(b, "%Y", v.id); + } + } + rules->destroy(rules); + b->end_list(b); + + b->begin_list(b, "certs"); + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &v)) + { + if (rule == AUTH_RULE_SUBJECT_CERT) + { + b->add_li(b, "%Y", v.cert->get_subject(v.cert)); + } + } + rules->destroy(rules); + b->end_list(b); + + b->begin_list(b, "cacerts"); + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &v)) + { + if (rule == AUTH_RULE_CA_CERT) + { + b->add_li(b, "%Y", v.cert->get_subject(v.cert)); + } + } + rules->destroy(rules); + b->end_list(b); + + b->end_section(b); + } + enumerator->destroy(enumerator); +} + +CALLBACK(list_conns, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + enumerator_t *enumerator, *tokens, *selectors, *children; + peer_cfg_t *peer_cfg; + ike_cfg_t *ike_cfg; + child_cfg_t *child_cfg; + char *ike, *str; + linked_list_t *list; + traffic_selector_t *ts; + vici_builder_t *b; + + ike = request->get_str(request, NULL, "ike"); + + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + NULL, NULL, NULL, NULL, IKE_ANY); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + if (ike && !streq(ike, peer_cfg->get_name(peer_cfg))) + { + continue; + } + + b = vici_builder_create(); + b->begin_section(b, peer_cfg->get_name(peer_cfg)); + + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + + b->begin_list(b, "local_addrs"); + str = ike_cfg->get_my_addr(ike_cfg); + tokens = enumerator_create_token(str, ",", " "); + while (tokens->enumerate(tokens, &str)) + { + b->add_li(b, "%s", str); + } + tokens->destroy(tokens); + b->end_list(b); + + b->begin_list(b, "remote_addrs"); + str = ike_cfg->get_other_addr(ike_cfg); + tokens = enumerator_create_token(str, ",", " "); + while (tokens->enumerate(tokens, &str)) + { + b->add_li(b, "%s", str); + } + tokens->destroy(tokens); + b->end_list(b); + + b->add_kv(b, "version", "%N", ike_version_names, + peer_cfg->get_ike_version(peer_cfg)); + + build_auth_cfgs(peer_cfg, TRUE, b); + build_auth_cfgs(peer_cfg, FALSE, b); + + b->begin_section(b, "children"); + + children = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (children->enumerate(children, &child_cfg)) + { + b->begin_section(b, child_cfg->get_name(child_cfg)); + + b->add_kv(b, "mode", "%N", ipsec_mode_names, + child_cfg->get_mode(child_cfg)); + + b->begin_list(b, "local-ts"); + list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + selectors = list->create_enumerator(list); + while (selectors->enumerate(selectors, &ts)) + { + b->add_li(b, "%R", ts); + } + selectors->destroy(selectors); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + b->end_list(b /* local-ts */); + + b->begin_list(b, "remote-ts"); + list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + selectors = list->create_enumerator(list); + while (selectors->enumerate(selectors, &ts)) + { + b->add_li(b, "%R", ts); + } + selectors->destroy(selectors); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + b->end_list(b /* remote-ts */); + + b->end_section(b); + } + children->destroy(children); + + b->end_section(b); /* children */ + + b->end_section(b); /* name */ + + this->dispatcher->raise_event(this->dispatcher, "list-conn", id, + b->finalize(b)); + } + enumerator->destroy(enumerator); + + b = vici_builder_create(); + return b->finalize(b); +} + +/** + * Do we have a private key for given certificate + */ +static bool has_privkey(private_vici_query_t *this, certificate_t *cert) +{ + private_key_t *private; + public_key_t *public; + identification_t *keyid; + chunk_t chunk; + bool found = FALSE; + + public = cert->get_public_key(cert); + if (public) + { + if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk)) + { + keyid = identification_create_from_encoding(ID_KEY_ID, chunk); + private = lib->credmgr->get_private(lib->credmgr, + public->get_type(public), keyid, NULL); + if (private) + { + found = TRUE; + private->destroy(private); + } + keyid->destroy(keyid); + } + public->destroy(public); + } + return found; +} + +CALLBACK(list_certs, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + enumerator_t *enumerator, *added; + linked_list_t *list; + certificate_t *cert, *current; + chunk_t encoding; + identification_t *subject = NULL; + int type; + vici_builder_t *b; + bool found; + char *str; + + str = request->get_str(request, "ANY", "type"); + if (!enum_from_name(certificate_type_names, str, &type)) + { + b = vici_builder_create(); + return b->finalize(b); + } + str = request->get_str(request, NULL, "subject"); + if (str) + { + subject = identification_create_from_string(str); + } + + list = linked_list_create(); + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + type, KEY_ANY, subject, FALSE); + while (enumerator->enumerate(enumerator, &cert)) + { + found = FALSE; + added = list->create_enumerator(list); + while (added->enumerate(added, ¤t)) + { + if (current->equals(current, cert)) + { + found = TRUE; + break; + } + } + added->destroy(added); + + if (!found && cert->get_encoding(cert, CERT_ASN1_DER, &encoding)) + { + b = vici_builder_create(); + b->add_kv(b, "type", "%N", + certificate_type_names, cert->get_type(cert)); + if (has_privkey(this, cert)) + { + b->add_kv(b, "has_privkey", "yes"); + } + b->add(b, VICI_KEY_VALUE, "data", encoding); + free(encoding.ptr); + + this->dispatcher->raise_event(this->dispatcher, "list-cert", id, + b->finalize(b)); + list->insert_last(list, cert->get_ref(cert)); + } + } + enumerator->destroy(enumerator); + + list->destroy_offset(list, offsetof(certificate_t, destroy)); + DESTROY_IF(subject); + + b = vici_builder_create(); + return b->finalize(b); +} + +CALLBACK(version, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + vici_builder_t *b; + + b = vici_builder_create(); + + b->add_kv(b, "daemon", "%s", lib->ns); + b->add_kv(b, "version", "%s", VERSION); + +#ifdef WIN32 + { + OSVERSIONINFOEX osvie; + + memset(&osvie, 0, sizeof(osvie)); + osvie.dwOSVersionInfoSize = sizeof(osvie); + + if (GetVersionEx((LPOSVERSIONINFO)&osvie)) + { + b->add_kv(b, "sysname", "Windows %s", + osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server"); + b->add_kv(b, "release", "%d.%d.%d (SP %d.%d)", + osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber, + osvie.wServicePackMajor, osvie.wServicePackMinor); + b->add_kv(b, "machine", "%s", +#ifdef WIN64 + "x86_64"); +#else + "x86"); +#endif /* !WIN64 */ + } + } +#else /* !WIN32 */ + { + struct utsname utsname; + + if (uname(&utsname) == 0) + { + b->add_kv(b, "sysname", "%s", utsname.sysname); + b->add_kv(b, "release", "%s", utsname.release); + b->add_kv(b, "machine", "%s", utsname.machine); + } + } +#endif /* !WIN32 */ + return b->finalize(b); +} + +/** + * Callback function for memusage summary + */ +CALLBACK(sum_usage, void, + vici_builder_t *b, int count, size_t bytes, int whitelisted) +{ + b->begin_section(b, "mem"); + b->add_kv(b, "total", "%zu", bytes); + b->add_kv(b, "allocs", "%d", count); + b->end_section(b); +} + +CALLBACK(stats, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + vici_builder_t *b; + enumerator_t *enumerator; + plugin_t *plugin; + time_t since, now; + int i; + + b = vici_builder_create(); + + now = time_monotonic(NULL); + since = time(NULL) - (now - this->uptime); + + b->begin_section(b, "uptime"); + b->add_kv(b, "running", "%V", &now, &this->uptime); + b->add_kv(b, "since", "%T", &since, FALSE); + b->end_section(b); + + b->begin_section(b, "workers"); + b->add_kv(b, "total", "%d", + lib->processor->get_total_threads(lib->processor)); + b->add_kv(b, "idle", "%d", + lib->processor->get_idle_threads(lib->processor)); + b->begin_section(b, "active"); + for (i = 0; i < JOB_PRIO_MAX; i++) + { + b->add_kv(b, enum_to_name(job_priority_names, i), "%d", + lib->processor->get_working_threads(lib->processor, i)); + } + b->end_section(b); + b->end_section(b); + + b->begin_section(b, "queues"); + for (i = 0; i < JOB_PRIO_MAX; i++) + { + b->add_kv(b, enum_to_name(job_priority_names, i), "%d", + lib->processor->get_job_load(lib->processor, i)); + } + b->end_section(b); + + b->add_kv(b, "scheduled", "%d", + lib->scheduler->get_job_load(lib->scheduler)); + + b->begin_section(b, "ikesas"); + b->add_kv(b, "total", "%u", + charon->ike_sa_manager->get_count(charon->ike_sa_manager)); + b->add_kv(b, "half-open", "%u", + charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager, + NULL)); + b->end_section(b); + + b->begin_list(b, "plugins"); + enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); + while (enumerator->enumerate(enumerator, &plugin, NULL)) + { + b->add_li(b, "%s", plugin->get_name(plugin)); + } + enumerator->destroy(enumerator); + b->end_list(b); + + if (lib->leak_detective) + { + lib->leak_detective->usage(lib->leak_detective, NULL, sum_usage, b); + } +#ifdef WIN32 + else + { + DWORD lasterr = ERROR_INVALID_HANDLE; + HANDLE heaps[32]; + int i, count; + char buf[16]; + size_t total = 0; + int allocs = 0; + + b->begin_section(b, "mem"); + count = GetProcessHeaps(countof(heaps), heaps); + for (i = 0; i < count; i++) + { + PROCESS_HEAP_ENTRY entry = {}; + size_t heap_total = 0; + int heap_allocs = 0; + + if (HeapLock(heaps[i])) + { + while (HeapWalk(heaps[i], &entry)) + { + if (entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) + { + heap_total += entry.cbData; + heap_allocs++; + } + } + lasterr = GetLastError(); + HeapUnlock(heaps[i]); + } + if (lasterr != ERROR_NO_MORE_ITEMS) + { + break; + } + snprintf(buf, sizeof(buf), "heap-%d", i); + b->begin_section(b, buf); + b->add_kv(b, "total", "%zu", heap_total); + b->add_kv(b, "allocs", "%d", heap_allocs); + b->end_section(b); + + total += heap_total; + allocs += heap_allocs; + } + if (lasterr == ERROR_NO_MORE_ITEMS) + { + b->add_kv(b, "total", "%zu", total); + b->add_kv(b, "allocs", "%d", allocs); + } + b->end_section(b); + } +#endif + +#ifdef HAVE_MALLINFO + { + struct mallinfo mi = mallinfo(); + + b->begin_section(b, "mallinfo"); + b->add_kv(b, "sbrk", "%d", mi.arena); + b->add_kv(b, "mmap", "%d", mi.hblkhd); + b->add_kv(b, "used", "%d", mi.uordblks); + b->add_kv(b, "free", "%d", mi.fordblks); + b->end_section(b); + } +#endif /* HAVE_MALLINFO */ + + return b->finalize(b); +} + +static void manage_command(private_vici_query_t *this, + char *name, vici_command_cb_t cb, bool reg) +{ + this->dispatcher->manage_command(this->dispatcher, name, + reg ? cb : NULL, this); +} + +/** + * (Un-)register dispatcher functions + */ +static void manage_commands(private_vici_query_t *this, bool reg) +{ + this->dispatcher->manage_event(this->dispatcher, "list-sa", reg); + this->dispatcher->manage_event(this->dispatcher, "list-policy", reg); + this->dispatcher->manage_event(this->dispatcher, "list-conn", reg); + this->dispatcher->manage_event(this->dispatcher, "list-cert", reg); + manage_command(this, "list-sas", list_sas, reg); + manage_command(this, "list-policies", list_policies, reg); + manage_command(this, "list-conns", list_conns, reg); + manage_command(this, "list-certs", list_certs, reg); + manage_command(this, "version", version, reg); + manage_command(this, "stats", stats, reg); +} + +METHOD(vici_query_t, destroy, void, + private_vici_query_t *this) +{ + manage_commands(this, FALSE); + free(this); +} + +/** + * See header + */ +vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher) +{ + private_vici_query_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + }, + .dispatcher = dispatcher, + .uptime = time_monotonic(NULL), + ); + + manage_commands(this, TRUE); + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_query.h b/src/libcharon/plugins/vici/vici_query.h new file mode 100644 index 000000000..da72b1411 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_query.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_query vici_query + * @{ @ingroup vici + */ + +#include "vici_dispatcher.h" + +#ifndef VICI_QUERY_H_ +#define VICI_QUERY_H_ + +typedef struct vici_query_t vici_query_t; + +/** + * Query helper, provides various commands to query/list daemon info. + */ +struct vici_query_t { + + /** + * Destroy a vici_query_t. + */ + void (*destroy)(vici_query_t *this); +}; + +/** + * Create a vici_query instance. + * + * @param dispatcher dispatcher to receive requests from + * @return query handler + */ +vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher); + +#endif /** VICI_QUERY_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_socket.c b/src/libcharon/plugins/vici/vici_socket.c new file mode 100644 index 000000000..916772871 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_socket.c @@ -0,0 +1,679 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_socket.h" + +#include <threading/mutex.h> +#include <threading/condvar.h> +#include <threading/thread.h> +#include <collections/array.h> +#include <collections/linked_list.h> +#include <processing/jobs/callback_job.h> + +#include <errno.h> +#include <string.h> + +typedef struct private_vici_socket_t private_vici_socket_t; + +/** + * Private members of vici_socket_t + */ +struct private_vici_socket_t { + + /** + * public functions + */ + vici_socket_t public; + + /** + * Inbound message callback + */ + vici_inbound_cb_t inbound; + + /** + * Client connect callback + */ + vici_connect_cb_t connect; + + /** + * Client disconnect callback + */ + vici_disconnect_cb_t disconnect; + + /** + * Next client connection identifier + */ + u_int nextid; + + /** + * User data for callbacks + */ + void *user; + + /** + * Service accepting vici connections + */ + stream_service_t *service; + + /** + * Client connections, as entry_t + */ + linked_list_t *connections; + + /** + * mutex for client connections + */ + mutex_t *mutex; +}; + +/** + * Data to securely reference an entry + */ +typedef struct { + /* reference to socket instance */ + private_vici_socket_t *this; + /** connection identifier of entry */ + u_int id; +} entry_selector_t; + +/** + * Partially processed message + */ +typedef struct { + /** bytes of length header sent/received */ + u_char hdrlen; + /** bytes of length header */ + char hdr[sizeof(u_int32_t)]; + /** send/receive buffer on heap */ + chunk_t buf; + /** bytes sent/received in buffer */ + u_int32_t done; +} msg_buf_t; + +/** + * Client connection entry + */ +typedef struct { + /** reference to socket */ + private_vici_socket_t *this; + /** associated stream */ + stream_t *stream; + /** queued messages to send, as msg_buf_t pointers */ + array_t *out; + /** input message buffer */ + msg_buf_t in; + /** queued input messages to process, as chunk_t */ + array_t *queue; + /** do we have job processing input queue? */ + bool has_processor; + /** client connection identifier */ + u_int id; + /** any users reading over this connection? */ + int readers; + /** any users writing over this connection? */ + int writers; + /** condvar to wait for usage */ + condvar_t *cond; +} entry_t; + +/** + * Destroy an connection entry + */ +CALLBACK(destroy_entry, void, + entry_t *entry) +{ + msg_buf_t *out; + chunk_t chunk; + + entry->stream->destroy(entry->stream); + entry->this->disconnect(entry->this->user, entry->id); + entry->cond->destroy(entry->cond); + + while (array_remove(entry->out, ARRAY_TAIL, &out)) + { + chunk_clear(&out->buf); + free(out); + } + array_destroy(entry->out); + while (array_remove(entry->queue, ARRAY_TAIL, &chunk)) + { + chunk_clear(&chunk); + } + array_destroy(entry->queue); + chunk_clear(&entry->in.buf); + free(entry); +} + +/** + * Find entry by stream (if given) or id, claim use + */ +static entry_t* find_entry(private_vici_socket_t *this, stream_t *stream, + u_int id, bool reader, bool writer) +{ + enumerator_t *enumerator; + entry_t *entry, *found = NULL; + bool candidate = TRUE; + + this->mutex->lock(this->mutex); + while (candidate && !found) + { + candidate = FALSE; + enumerator = this->connections->create_enumerator(this->connections); + while (enumerator->enumerate(enumerator, &entry)) + { + if (stream) + { + if (entry->stream != stream) + { + continue; + } + } + else + { + if (entry->id != id) + { + continue; + } + } + candidate = TRUE; + + if ((reader && entry->readers) || + (writer && entry->writers)) + { + entry->cond->wait(entry->cond, this->mutex); + break; + } + if (reader) + { + entry->readers++; + } + if (writer) + { + entry->writers++; + } + found = entry; + break; + } + enumerator->destroy(enumerator); + } + this->mutex->unlock(this->mutex); + + return found; +} + +/** + * Remove entry by id, claim use + */ +static entry_t* remove_entry(private_vici_socket_t *this, u_int id) +{ + enumerator_t *enumerator; + entry_t *entry, *found = NULL; + bool candidate = TRUE; + + this->mutex->lock(this->mutex); + while (candidate && !found) + { + candidate = FALSE; + enumerator = this->connections->create_enumerator(this->connections); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->id == id) + { + candidate = TRUE; + if (entry->readers || entry->writers) + { + entry->cond->wait(entry->cond, this->mutex); + break; + } + this->connections->remove_at(this->connections, enumerator); + found = entry; + break; + } + } + enumerator->destroy(enumerator); + } + this->mutex->unlock(this->mutex); + + return found; +} + +/** + * Release a claimed entry + */ +static void put_entry(private_vici_socket_t *this, entry_t *entry, + bool reader, bool writer) +{ + this->mutex->lock(this->mutex); + if (reader) + { + entry->readers--; + } + if (writer) + { + entry->writers--; + } + entry->cond->signal(entry->cond); + this->mutex->unlock(this->mutex); +} + +/** + * Asynchronous callback to disconnect client + */ +CALLBACK(disconnect_async, job_requeue_t, + entry_selector_t *sel) +{ + entry_t *entry; + + entry = remove_entry(sel->this, sel->id); + if (entry) + { + destroy_entry(entry); + } + return JOB_REQUEUE_NONE; +} + +/** + * Disconnect a connected client + */ +static void disconnect(private_vici_socket_t *this, u_int id) +{ + entry_selector_t *sel; + + INIT(sel, + .this = this, + .id = id, + ); + + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create(disconnect_async, sel, free, NULL)); +} + +/** + * Write queued output data + */ +static bool do_write(private_vici_socket_t *this, entry_t *entry, + stream_t *stream) +{ + msg_buf_t *out; + ssize_t len; + + while (array_get(entry->out, ARRAY_HEAD, &out)) + { + /* write header */ + while (out->hdrlen < sizeof(out->hdr)) + { + len = stream->write(stream, out->hdr + out->hdrlen, + sizeof(out->hdr) - out->hdrlen, FALSE); + if (len == 0) + { + return FALSE; + } + if (len < 0) + { + if (errno == EWOULDBLOCK) + { + return TRUE; + } + DBG1(DBG_CFG, "vici header write error: %s", strerror(errno)); + return FALSE; + } + out->hdrlen += len; + } + + /* write buffer buffer */ + while (out->buf.len > out->done) + { + len = stream->write(stream, out->buf.ptr + out->done, + out->buf.len - out->done, FALSE); + if (len == 0) + { + DBG1(DBG_CFG, "premature vici disconnect"); + return FALSE; + } + if (len < 0) + { + if (errno == EWOULDBLOCK) + { + return TRUE; + } + DBG1(DBG_CFG, "vici write error: %s", strerror(errno)); + return FALSE; + } + out->done += len; + } + + if (array_remove(entry->out, ARRAY_HEAD, &out)) + { + chunk_clear(&out->buf); + free(out); + } + } + return TRUE; +} + +/** + * Send pending messages + */ +CALLBACK(on_write, bool, + private_vici_socket_t *this, stream_t *stream) +{ + entry_t *entry; + bool ret = FALSE; + + entry = find_entry(this, stream, 0, FALSE, TRUE); + if (entry) + { + ret = do_write(this, entry, stream); + if (ret) + { + /* unregister if we have no more messages to send */ + ret = array_count(entry->out) != 0; + } + else + { + disconnect(entry->this, entry->id); + } + put_entry(this, entry, FALSE, TRUE); + } + + return ret; +} + +/** + * Read in available header with data, non-blocking cumulating to buffer + */ +static bool do_read(private_vici_socket_t *this, entry_t *entry, + stream_t *stream) +{ + u_int32_t msglen; + ssize_t len; + + /* assemble the length header first */ + while (entry->in.hdrlen < sizeof(entry->in.hdr)) + { + len = stream->read(stream, entry->in.hdr + entry->in.hdrlen, + sizeof(entry->in.hdr) - entry->in.hdrlen, FALSE); + if (len == 0) + { + return FALSE; + } + if (len < 0) + { + if (errno == EWOULDBLOCK) + { + return TRUE; + } + DBG1(DBG_CFG, "vici header read error: %s", strerror(errno)); + return FALSE; + } + entry->in.hdrlen += len; + if (entry->in.hdrlen == sizeof(entry->in.hdr)) + { + msglen = untoh32(entry->in.hdr); + if (msglen > VICI_MESSAGE_SIZE_MAX) + { + DBG1(DBG_CFG, "vici message length %u exceeds %u bytes limit, " + "ignored", msglen, VICI_MESSAGE_SIZE_MAX); + return FALSE; + } + /* header complete, continue with data */ + entry->in.buf = chunk_alloc(msglen); + } + } + + /* assemble buffer */ + while (entry->in.buf.len > entry->in.done) + { + len = stream->read(stream, entry->in.buf.ptr + entry->in.done, + entry->in.buf.len - entry->in.done, FALSE); + if (len == 0) + { + DBG1(DBG_CFG, "premature vici disconnect"); + return FALSE; + } + if (len < 0) + { + if (errno == EWOULDBLOCK) + { + return TRUE; + } + DBG1(DBG_CFG, "vici read error: %s", strerror(errno)); + return FALSE; + } + entry->in.done += len; + } + + return TRUE; +} + +/** + * Callback processing incoming requestes in strict order + */ +CALLBACK(process_queue, job_requeue_t, + entry_selector_t *sel) +{ + entry_t *entry; + chunk_t chunk; + bool found; + u_int id; + + while (TRUE) + { + entry = find_entry(sel->this, NULL, sel->id, TRUE, FALSE); + if (!entry) + { + break; + } + + found = array_remove(entry->queue, ARRAY_HEAD, &chunk); + if (!found) + { + entry->has_processor = FALSE; + } + id = entry->id; + put_entry(sel->this, entry, TRUE, FALSE); + if (!found) + { + break; + } + + thread_cleanup_push(free, chunk.ptr); + sel->this->inbound(sel->this->user, id, chunk); + thread_cleanup_pop(TRUE); + } + return JOB_REQUEUE_NONE; +} + +/** + * Process incoming messages + */ +CALLBACK(on_read, bool, + private_vici_socket_t *this, stream_t *stream) +{ + entry_selector_t *sel; + entry_t *entry; + bool ret = FALSE; + + entry = find_entry(this, stream, 0, TRUE, FALSE); + if (entry) + { + ret = do_read(this, entry, stream); + if (!ret) + { + disconnect(this, entry->id); + } + else if (entry->in.hdrlen == sizeof(entry->in.hdr) && + entry->in.buf.len == entry->in.done) + { + array_insert(entry->queue, ARRAY_TAIL, &entry->in.buf); + entry->in.buf = chunk_empty; + entry->in.hdrlen = entry->in.done = 0; + + if (!entry->has_processor) + { + INIT(sel, + .this = this, + .id = entry->id, + ); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create(process_queue, + sel, free, NULL)); + entry->has_processor = TRUE; + } + } + put_entry(this, entry, TRUE, FALSE); + } + + return ret; +} + +/** + * Process connection request + */ +CALLBACK(on_accept, bool, + private_vici_socket_t *this, stream_t *stream) +{ + entry_t *entry; + u_int id; + + id = ref_get(&this->nextid); + + INIT(entry, + .this = this, + .stream = stream, + .id = id, + .out = array_create(0, 0), + .queue = array_create(sizeof(chunk_t), 0), + .cond = condvar_create(CONDVAR_TYPE_DEFAULT), + .readers = 1, + ); + + this->mutex->lock(this->mutex); + this->connections->insert_last(this->connections, entry); + this->mutex->unlock(this->mutex); + + stream->on_read(stream, on_read, this); + + put_entry(this, entry, TRUE, FALSE); + + this->connect(this->user, id); + + return TRUE; +} + +/** + * Async callback to enable writer + */ +CALLBACK(enable_writer, job_requeue_t, + entry_selector_t *sel) +{ + entry_t *entry; + + entry = find_entry(sel->this, NULL, sel->id, FALSE, TRUE); + if (entry) + { + entry->stream->on_write(entry->stream, on_write, sel->this); + put_entry(sel->this, entry, FALSE, TRUE); + } + return JOB_REQUEUE_NONE; +} + +METHOD(vici_socket_t, send_, void, + private_vici_socket_t *this, u_int id, chunk_t msg) +{ + if (msg.len <= VICI_MESSAGE_SIZE_MAX) + { + entry_selector_t *sel; + msg_buf_t *out; + entry_t *entry; + + entry = find_entry(this, NULL, id, FALSE, TRUE); + if (entry) + { + INIT(out, + .buf = msg, + ); + htoun32(out->hdr, msg.len); + + array_insert(entry->out, ARRAY_TAIL, out); + if (array_count(entry->out) == 1) + { /* asynchronously re-enable on_write callback when we get data */ + INIT(sel, + .this = this, + .id = entry->id, + ); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create(enable_writer, + sel, free, NULL)); + } + put_entry(this, entry, FALSE, TRUE); + } + else + { + DBG1(DBG_CFG, "vici connection %u unknown", id); + chunk_clear(&msg); + } + } + else + { + DBG1(DBG_CFG, "vici message size %zu exceeds maximum size of %u, " + "discarded", msg.len, VICI_MESSAGE_SIZE_MAX); + chunk_clear(&msg); + } +} + +METHOD(vici_socket_t, destroy, void, + private_vici_socket_t *this) +{ + DESTROY_IF(this->service); + this->connections->destroy_function(this->connections, destroy_entry); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +vici_socket_t *vici_socket_create(char *uri, vici_inbound_cb_t inbound, + vici_connect_cb_t connect, + vici_disconnect_cb_t disconnect, void *user) +{ + private_vici_socket_t *this; + + INIT(this, + .public = { + .send = _send_, + .destroy = _destroy, + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .connections = linked_list_create(), + .inbound = inbound, + .connect = connect, + .disconnect = disconnect, + .user = user, + ); + + this->service = lib->streams->create_service(lib->streams, uri, 3); + if (!this->service) + { + DBG1(DBG_CFG, "creating vici socket failed"); + destroy(this); + return NULL; + } + this->service->on_accept(this->service, on_accept, this, + JOB_PRIO_CRITICAL, 0); + + return &this->public; +} diff --git a/src/libcharon/plugins/vici/vici_socket.h b/src/libcharon/plugins/vici/vici_socket.h new file mode 100644 index 000000000..872783665 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_socket.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_socket vici_socket + * @{ @ingroup vici + */ + +#ifndef VICI_SOCKET_H_ +#define VICI_SOCKET_H_ + +#include <library.h> + +/** + * Maximum size of a single message exchanged. + */ +#define VICI_MESSAGE_SIZE_MAX (512 * 1024) + +typedef struct vici_socket_t vici_socket_t; + +/** + * Callback function for dispatching inbound client messages. + * + * @param user user data, as passed during registration + * @param id unique client connection identifier + * @param data incoming message data + */ +typedef void (*vici_inbound_cb_t)(void *user, u_int id, chunk_t data); + +/** + * Callback function invoked when new clients connect + * + * @param user user data, as passed during registration + * @param id unique client connection identifier + * @return client connection context + */ +typedef void (*vici_connect_cb_t)(void *user, u_int id); + +/** + * Callback function invoked when connected clients disconnect + * + * @param user user data, as passed during registration + * @param id unique client connection identifier + */ +typedef void (*vici_disconnect_cb_t)(void *user, u_int id); + +/** + * Vici socket, low level socket input/output handling. + * + * On the socket, we pass raw chunks having a 2 byte network order length + * prefix. The length field does not count the length header itself, and + * is not included in the data passed over this interface. + */ +struct vici_socket_t { + + /** + * Send a message to a client identified by connection identifier. + * + * @param id unique client connection identifier + * @param data data to send to client, gets owned + */ + void (*send)(vici_socket_t *this, u_int id, chunk_t data); + + /** + * Destroy socket. + */ + void (*destroy)(vici_socket_t *this); +}; + +/** + * Create a vici_socket instance. + * + * @param uri socket URI to listen on + * @param inbound inbound message callback + * @param connect connect callback + * @param disconnect disconnect callback + * @param user user data to pass to callbacks + */ +vici_socket_t *vici_socket_create(char *uri, vici_inbound_cb_t inbound, + vici_connect_cb_t connect, + vici_disconnect_cb_t disconnect, void *user); + +#endif /** VICI_SOCKET_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_tests.c b/src/libcharon/plugins/vici/vici_tests.c new file mode 100644 index 000000000..434aa5e18 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_tests.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <test_runner.h> + +#include <daemon.h> +#include <hydra.h> + +/* declare test suite constructors */ +#define TEST_SUITE(x) test_suite_t* x(); +#include "vici_tests.h" +#undef TEST_SUITE + +static test_configuration_t tests[] = { +#define TEST_SUITE(x) \ + { .suite = x, }, +#include "vici_tests.h" + { .suite = NULL, } +}; + +static bool test_runner_init(bool init) +{ + if (!init) + { + lib->processor->set_threads(lib->processor, 0); + lib->processor->cancel(lib->processor); + } + return TRUE; +} + +int main(int argc, char *argv[]) +{ + return test_runner_run("vici", tests, test_runner_init); +} diff --git a/src/libcharon/plugins/vici/vici_tests.h b/src/libcharon/plugins/vici/vici_tests.h new file mode 100644 index 000000000..3e8f170e4 --- /dev/null +++ b/src/libcharon/plugins/vici/vici_tests.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +TEST_SUITE(socket_suite_create) +TEST_SUITE(message_suite_create) +TEST_SUITE(request_suite_create) +TEST_SUITE(event_suite_create) diff --git a/src/libcharon/plugins/whitelist/Makefile.am b/src/libcharon/plugins/whitelist/Makefile.am index e02b4a041..1fd01c888 100644 --- a/src/libcharon/plugins/whitelist/Makefile.am +++ b/src/libcharon/plugins/whitelist/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-whitelist.la diff --git a/src/libcharon/plugins/whitelist/Makefile.in b/src/libcharon/plugins/whitelist/Makefile.in index e3588ad7d..8a714a9ea 100644 --- a/src/libcharon/plugins/whitelist/Makefile.in +++ b/src/libcharon/plugins/whitelist/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -273,6 +273,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -291,6 +292,7 @@ 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@ @@ -318,6 +320,7 @@ 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@ @@ -409,6 +412,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -426,7 +430,7 @@ AM_CPPFLAGS = \ -DIPSEC_PIDDIR=\"${piddir}\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-whitelist.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-whitelist.la diff --git a/src/libcharon/plugins/xauth_eap/Makefile.am b/src/libcharon/plugins/xauth_eap/Makefile.am index 21f8d0297..ea75c1581 100644 --- a/src/libcharon/plugins/xauth_eap/Makefile.am +++ b/src/libcharon/plugins/xauth_eap/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-xauth-eap.la diff --git a/src/libcharon/plugins/xauth_eap/Makefile.in b/src/libcharon/plugins/xauth_eap/Makefile.in index b78a91764..26bb6fb1a 100644 --- a/src/libcharon/plugins/xauth_eap/Makefile.in +++ b/src/libcharon/plugins/xauth_eap/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-xauth-eap.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-xauth-eap.la diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap.c b/src/libcharon/plugins/xauth_eap/xauth_eap.c index f597bb7ae..f21d02697 100644 --- a/src/libcharon/plugins/xauth_eap/xauth_eap.c +++ b/src/libcharon/plugins/xauth_eap/xauth_eap.c @@ -163,11 +163,11 @@ METHOD(xauth_method_t, initiate, status_t, { cp_payload_t *cp; - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST); cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, chunk_empty)); cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_PASSWORD, chunk_empty)); *out = cp; return NEED_MORE; } diff --git a/src/libcharon/plugins/xauth_generic/Makefile.am b/src/libcharon/plugins/xauth_generic/Makefile.am index d48e52ddd..1ecd9fd14 100644 --- a/src/libcharon/plugins/xauth_generic/Makefile.am +++ b/src/libcharon/plugins/xauth_generic/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-xauth-generic.la diff --git a/src/libcharon/plugins/xauth_generic/Makefile.in b/src/libcharon/plugins/xauth_generic/Makefile.in index e4d96a954..f06fdb593 100644 --- a/src/libcharon/plugins/xauth_generic/Makefile.in +++ b/src/libcharon/plugins/xauth_generic/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-xauth-generic.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-xauth-generic.la diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.c b/src/libcharon/plugins/xauth_generic/xauth_generic.c index 5df8aadee..c37da0cb0 100644 --- a/src/libcharon/plugins/xauth_generic/xauth_generic.c +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.c @@ -69,7 +69,7 @@ METHOD(xauth_method_t, process_peer, status_t, } enumerator->destroy(enumerator); - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY); enumerator = in->create_attribute_enumerator(in); while (enumerator->enumerate(enumerator, &attr)) @@ -80,7 +80,7 @@ METHOD(xauth_method_t, process_peer, status_t, { case XAUTH_USER_NAME: cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, this->peer->get_encoding(this->peer))); break; case XAUTH_NEXT_PIN: @@ -99,7 +99,7 @@ METHOD(xauth_method_t, process_peer, status_t, return FAILED; } cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, attr->get_type(attr), + PLV1_CONFIGURATION_ATTRIBUTE, attr->get_type(attr), shared->get_key(shared))); shared->destroy(shared); break; @@ -118,11 +118,11 @@ METHOD(xauth_method_t, initiate_server, status_t, { cp_payload_t *cp; - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST); cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, chunk_empty)); cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_PASSWORD, chunk_empty)); *out = cp; return NEED_MORE; } diff --git a/src/libcharon/plugins/xauth_noauth/Makefile.am b/src/libcharon/plugins/xauth_noauth/Makefile.am index f1581ba67..3902471fe 100644 --- a/src/libcharon/plugins/xauth_noauth/Makefile.am +++ b/src/libcharon/plugins/xauth_noauth/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-xauth-noauth.la diff --git a/src/libcharon/plugins/xauth_noauth/Makefile.in b/src/libcharon/plugins/xauth_noauth/Makefile.in index 5fe4c064f..72f3dc668 100644 --- a/src/libcharon/plugins/xauth_noauth/Makefile.in +++ b/src/libcharon/plugins/xauth_noauth/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-xauth-noauth.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-xauth-noauth.la diff --git a/src/libcharon/plugins/xauth_pam/Makefile.am b/src/libcharon/plugins/xauth_pam/Makefile.am index 1875f81d3..abf83ca75 100644 --- a/src/libcharon/plugins/xauth_pam/Makefile.am +++ b/src/libcharon/plugins/xauth_pam/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-xauth-pam.la diff --git a/src/libcharon/plugins/xauth_pam/Makefile.in b/src/libcharon/plugins/xauth_pam/Makefile.in index 2a6aec0c3..9af015e29 100644 --- a/src/libcharon/plugins/xauth_pam/Makefile.in +++ b/src/libcharon/plugins/xauth_pam/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ 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@ @@ -311,6 +313,7 @@ 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@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-xauth-pam.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-xauth-pam.la diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam.c b/src/libcharon/plugins/xauth_pam/xauth_pam.c index 71c79ecc0..3414d2ec8 100644 --- a/src/libcharon/plugins/xauth_pam/xauth_pam.c +++ b/src/libcharon/plugins/xauth_pam/xauth_pam.c @@ -43,11 +43,11 @@ METHOD(xauth_method_t, initiate, status_t, { cp_payload_t *cp; - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST); cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, chunk_empty)); cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_PASSWORD, chunk_empty)); *out = cp; return NEED_MORE; } @@ -153,7 +153,12 @@ METHOD(xauth_method_t, process, status_t, attr2string(user, sizeof(user), chunk); break; case XAUTH_USER_PASSWORD: - attr2string(pass, sizeof(pass), attr->get_chunk(attr)); + chunk = attr->get_chunk(attr); + if (chunk.len && chunk.ptr[chunk.len - 1] == 0) + { /* fix null-terminated passwords (Android etc.) */ + chunk.len -= 1; + } + attr2string(pass, sizeof(pass), chunk); break; default: break; diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam_listener.h b/src/libcharon/plugins/xauth_pam/xauth_pam_listener.h index 5b15410f4..fd1122395 100644 --- a/src/libcharon/plugins/xauth_pam/xauth_pam_listener.h +++ b/src/libcharon/plugins/xauth_pam/xauth_pam_listener.h @@ -26,7 +26,7 @@ * @{ @ingroup xauth_pam */ -#ifndef XAUTH_PAM_LISENER_H_ +#ifndef XAUTH_PAM_LISTENER_H_ #define XAUTH_PAM_LISTENER_H_ typedef struct xauth_pam_listener_t xauth_pam_listener_t; |