summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins')
-rw-r--r--src/libcharon/plugins/addrblock/Makefile.am18
-rw-r--r--src/libcharon/plugins/addrblock/Makefile.in (renamed from src/libcharon/plugins/resolve/Makefile.in)59
-rw-r--r--src/libcharon/plugins/addrblock/addrblock_narrow.c154
-rw-r--r--src/libcharon/plugins/addrblock/addrblock_narrow.h49
-rw-r--r--src/libcharon/plugins/addrblock/addrblock_plugin.c72
-rw-r--r--src/libcharon/plugins/addrblock/addrblock_plugin.h (renamed from src/libcharon/plugins/resolve/resolve_plugin.h)24
-rw-r--r--src/libcharon/plugins/addrblock/addrblock_validator.c124
-rw-r--r--src/libcharon/plugins/addrblock/addrblock_validator.h49
-rw-r--r--src/libcharon/plugins/android/Makefile.am5
-rw-r--r--src/libcharon/plugins/android/Makefile.in13
-rw-r--r--src/libcharon/plugins/android/android_creds.c294
-rw-r--r--src/libcharon/plugins/android/android_creds.h73
-rw-r--r--src/libcharon/plugins/android/android_handler.c4
-rw-r--r--src/libcharon/plugins/android/android_logger.c96
-rw-r--r--src/libcharon/plugins/android/android_logger.h (renamed from src/libcharon/plugins/resolve/resolve_handler.h)35
-rw-r--r--src/libcharon/plugins/android/android_plugin.c41
-rw-r--r--src/libcharon/plugins/android/android_service.c385
-rw-r--r--src/libcharon/plugins/android/android_service.h54
-rw-r--r--src/libcharon/plugins/dhcp/Makefile.in2
-rw-r--r--src/libcharon/plugins/dhcp/dhcp_provider.c3
-rw-r--r--src/libcharon/plugins/eap_aka/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_aka/eap_aka_peer.c1
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp2/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c3
-rw-r--r--src/libcharon/plugins/eap_gtc/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_gtc/eap_gtc.c4
-rw-r--r--src/libcharon/plugins/eap_identity/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_md5/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_md5/eap_md5.c3
-rw-r--r--src/libcharon/plugins/eap_mschapv2/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c8
-rw-r--r--src/libcharon/plugins/eap_radius/Makefile.am2
-rw-r--r--src/libcharon/plugins/eap_radius/Makefile.in9
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius.c131
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_plugin.c150
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_plugin.h8
-rw-r--r--src/libcharon/plugins/eap_radius/radius_client.c464
-rw-r--r--src/libcharon/plugins/eap_radius/radius_client.h34
-rw-r--r--src/libcharon/plugins/eap_radius/radius_message.c123
-rw-r--r--src/libcharon/plugins/eap_radius/radius_server.c212
-rw-r--r--src/libcharon/plugins/eap_radius/radius_server.h88
-rw-r--r--src/libcharon/plugins/eap_radius/radius_socket.c309
-rw-r--r--src/libcharon/plugins/eap_radius/radius_socket.h74
-rw-r--r--src/libcharon/plugins/eap_sim/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_sim/eap_sim_peer.c1
-rw-r--r--src/libcharon/plugins/eap_sim_file/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_simaka_reauth/Makefile.in2
-rw-r--r--src/libcharon/plugins/eap_simaka_sql/Makefile.am18
-rw-r--r--src/libcharon/plugins/eap_simaka_sql/Makefile.in592
-rw-r--r--src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c177
-rw-r--r--src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.h54
-rw-r--r--src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.c100
-rw-r--r--src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.h42
-rw-r--r--src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_provider.c180
-rw-r--r--src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_provider.h54
-rw-r--r--src/libcharon/plugins/farp/Makefile.in2
-rw-r--r--src/libcharon/plugins/farp/farp_spoofer.c4
-rw-r--r--src/libcharon/plugins/ha/Makefile.am4
-rw-r--r--src/libcharon/plugins/ha/Makefile.in11
-rw-r--r--src/libcharon/plugins/ha/ha_attribute.c364
-rw-r--r--src/libcharon/plugins/ha/ha_attribute.h60
-rw-r--r--src/libcharon/plugins/ha/ha_cache.c362
-rw-r--r--src/libcharon/plugins/ha/ha_cache.h78
-rw-r--r--src/libcharon/plugins/ha/ha_child.c84
-rw-r--r--src/libcharon/plugins/ha/ha_child.h12
-rw-r--r--src/libcharon/plugins/ha/ha_ctl.c26
-rw-r--r--src/libcharon/plugins/ha/ha_ctl.h6
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c209
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.h11
-rw-r--r--src/libcharon/plugins/ha/ha_ike.c101
-rw-r--r--src/libcharon/plugins/ha/ha_ike.h11
-rw-r--r--src/libcharon/plugins/ha/ha_kernel.c96
-rw-r--r--src/libcharon/plugins/ha/ha_kernel.h28
-rw-r--r--src/libcharon/plugins/ha/ha_message.c102
-rw-r--r--src/libcharon/plugins/ha/ha_message.h26
-rw-r--r--src/libcharon/plugins/ha/ha_plugin.c45
-rw-r--r--src/libcharon/plugins/ha/ha_plugin.h2
-rw-r--r--src/libcharon/plugins/ha/ha_segments.c220
-rw-r--r--src/libcharon/plugins/ha/ha_segments.h23
-rw-r--r--src/libcharon/plugins/ha/ha_socket.c58
-rw-r--r--src/libcharon/plugins/ha/ha_socket.h4
-rw-r--r--src/libcharon/plugins/ha/ha_tunnel.c78
-rw-r--r--src/libcharon/plugins/ha/ha_tunnel.h2
-rw-r--r--src/libcharon/plugins/kernel_klips/Makefile.in2
-rw-r--r--src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.c27
-rw-r--r--src/libcharon/plugins/kernel_netlink/Makefile.in2
-rw-r--r--src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c323
-rw-r--r--src/libcharon/plugins/kernel_pfkey/Makefile.in2
-rw-r--r--src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c125
-rw-r--r--src/libcharon/plugins/kernel_pfroute/Makefile.in2
-rw-r--r--src/libcharon/plugins/load_tester/Makefile.in2
-rw-r--r--src/libcharon/plugins/load_tester/load_tester_config.c5
-rw-r--r--src/libcharon/plugins/load_tester/load_tester_ipsec.c154
-rw-r--r--src/libcharon/plugins/load_tester/load_tester_plugin.c4
-rw-r--r--src/libcharon/plugins/medcli/Makefile.in2
-rw-r--r--src/libcharon/plugins/medcli/medcli_config.c8
-rw-r--r--src/libcharon/plugins/medcli/medcli_plugin.c4
-rw-r--r--src/libcharon/plugins/medsrv/Makefile.in2
-rw-r--r--src/libcharon/plugins/medsrv/medsrv_plugin.c4
-rw-r--r--src/libcharon/plugins/nm/Makefile.in2
-rw-r--r--src/libcharon/plugins/nm/nm_plugin.c4
-rw-r--r--src/libcharon/plugins/nm/nm_service.c3
-rw-r--r--src/libcharon/plugins/resolve/Makefile.am18
-rw-r--r--src/libcharon/plugins/resolve/resolve_handler.c251
-rw-r--r--src/libcharon/plugins/resolve/resolve_plugin.c62
-rw-r--r--src/libcharon/plugins/smp/Makefile.in2
-rw-r--r--src/libcharon/plugins/socket_default/Makefile.in2
-rw-r--r--src/libcharon/plugins/socket_dynamic/Makefile.in2
-rw-r--r--src/libcharon/plugins/socket_raw/Makefile.in2
-rw-r--r--src/libcharon/plugins/socket_raw/socket_raw_socket.c14
-rw-r--r--src/libcharon/plugins/sql/Makefile.in2
-rw-r--r--src/libcharon/plugins/sql/sql_config.c2
-rw-r--r--src/libcharon/plugins/sql/sql_plugin.c4
-rw-r--r--src/libcharon/plugins/stroke/Makefile.in2
-rw-r--r--src/libcharon/plugins/stroke/stroke_ca.c23
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c22
-rw-r--r--src/libcharon/plugins/stroke/stroke_control.c5
-rw-r--r--src/libcharon/plugins/stroke/stroke_cred.c10
-rw-r--r--src/libcharon/plugins/stroke/stroke_list.c59
-rw-r--r--src/libcharon/plugins/stroke/stroke_socket.c11
-rw-r--r--src/libcharon/plugins/uci/Makefile.in2
-rw-r--r--src/libcharon/plugins/uci/uci_config.c3
-rw-r--r--src/libcharon/plugins/uci/uci_plugin.c4
-rw-r--r--src/libcharon/plugins/unit_tester/Makefile.am3
-rw-r--r--src/libcharon/plugins/unit_tester/Makefile.in15
-rw-r--r--src/libcharon/plugins/unit_tester/tests.h1
-rw-r--r--src/libcharon/plugins/unit_tester/tests/test_auth_info.c2
-rw-r--r--src/libcharon/plugins/unit_tester/tests/test_hashtable.c111
-rw-r--r--src/libcharon/plugins/unit_tester/tests/test_med_db.c6
-rw-r--r--src/libcharon/plugins/updown/Makefile.in2
-rw-r--r--src/libcharon/plugins/updown/updown_listener.c71
132 files changed, 6093 insertions, 1741 deletions
diff --git a/src/libcharon/plugins/addrblock/Makefile.am b/src/libcharon/plugins/addrblock/Makefile.am
new file mode 100644
index 000000000..50d0457f8
--- /dev/null
+++ b/src/libcharon/plugins/addrblock/Makefile.am
@@ -0,0 +1,18 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-addrblock.la
+else
+plugin_LTLIBRARIES = libstrongswan-addrblock.la
+endif
+
+libstrongswan_addrblock_la_SOURCES = \
+ addrblock_plugin.h addrblock_plugin.c \
+ addrblock_narrow.h addrblock_narrow.c \
+ addrblock_validator.h addrblock_validator.c
+
+libstrongswan_addrblock_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/resolve/Makefile.in b/src/libcharon/plugins/addrblock/Makefile.in
index 92ee85539..4cb047929 100644
--- a/src/libcharon/plugins/resolve/Makefile.in
+++ b/src/libcharon/plugins/addrblock/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -34,7 +34,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-subdir = src/libcharon/plugins/resolve
+subdir = src/libcharon/plugins/addrblock
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
@@ -73,17 +73,18 @@ am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__installdirs = "$(DESTDIR)$(plugindir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
-libstrongswan_resolve_la_LIBADD =
-am_libstrongswan_resolve_la_OBJECTS = resolve_plugin.lo \
- resolve_handler.lo
-libstrongswan_resolve_la_OBJECTS = \
- $(am_libstrongswan_resolve_la_OBJECTS)
-libstrongswan_resolve_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libstrongswan_resolve_la_LDFLAGS) $(LDFLAGS) -o $@
-@MONOLITHIC_FALSE@am_libstrongswan_resolve_la_rpath = -rpath \
+libstrongswan_addrblock_la_LIBADD =
+am_libstrongswan_addrblock_la_OBJECTS = addrblock_plugin.lo \
+ addrblock_narrow.lo addrblock_validator.lo
+libstrongswan_addrblock_la_OBJECTS = \
+ $(am_libstrongswan_addrblock_la_OBJECTS)
+libstrongswan_addrblock_la_LINK = $(LIBTOOL) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_addrblock_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@MONOLITHIC_FALSE@am_libstrongswan_addrblock_la_rpath = -rpath \
@MONOLITHIC_FALSE@ $(plugindir)
-@MONOLITHIC_TRUE@am_libstrongswan_resolve_la_rpath =
+@MONOLITHIC_TRUE@am_libstrongswan_addrblock_la_rpath =
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@@ -97,8 +98,8 @@ CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
-SOURCES = $(libstrongswan_resolve_la_SOURCES)
-DIST_SOURCES = $(libstrongswan_resolve_la_SOURCES)
+SOURCES = $(libstrongswan_addrblock_la_SOURCES)
+DIST_SOURCES = $(libstrongswan_addrblock_la_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -260,16 +261,15 @@ xml_LIBS = @xml_LIBS@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
-I$(top_srcdir)/src/libcharon
-AM_CFLAGS = -rdynamic \
- -DRESOLV_CONF=\"${resolv_conf}\"
-
-@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-resolve.la
-@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-resolve.la
-libstrongswan_resolve_la_SOURCES = \
- resolve_plugin.h resolve_plugin.c \
- resolve_handler.h resolve_handler.c
+AM_CFLAGS = -rdynamic
+@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-addrblock.la
+@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-addrblock.la
+libstrongswan_addrblock_la_SOURCES = \
+ addrblock_plugin.h addrblock_plugin.c \
+ addrblock_narrow.h addrblock_narrow.c \
+ addrblock_validator.h addrblock_validator.c
-libstrongswan_resolve_la_LDFLAGS = -module -avoid-version
+libstrongswan_addrblock_la_LDFLAGS = -module -avoid-version
all: all-am
.SUFFIXES:
@@ -283,9 +283,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/resolve/Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/addrblock/Makefile'; \
$(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --gnu src/libcharon/plugins/resolve/Makefile
+ $(AUTOMAKE) --gnu src/libcharon/plugins/addrblock/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
@@ -344,8 +344,8 @@ clean-pluginLTLIBRARIES:
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
-libstrongswan-resolve.la: $(libstrongswan_resolve_la_OBJECTS) $(libstrongswan_resolve_la_DEPENDENCIES)
- $(libstrongswan_resolve_la_LINK) $(am_libstrongswan_resolve_la_rpath) $(libstrongswan_resolve_la_OBJECTS) $(libstrongswan_resolve_la_LIBADD) $(LIBS)
+libstrongswan-addrblock.la: $(libstrongswan_addrblock_la_OBJECTS) $(libstrongswan_addrblock_la_DEPENDENCIES)
+ $(libstrongswan_addrblock_la_LINK) $(am_libstrongswan_addrblock_la_rpath) $(libstrongswan_addrblock_la_OBJECTS) $(libstrongswan_addrblock_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -353,8 +353,9 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve_handler.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve_plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrblock_narrow.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrblock_plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrblock_validator.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/src/libcharon/plugins/addrblock/addrblock_narrow.c b/src/libcharon/plugins/addrblock/addrblock_narrow.c
new file mode 100644
index 000000000..f85fa78d6
--- /dev/null
+++ b/src/libcharon/plugins/addrblock/addrblock_narrow.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ * Copyright (C) 2009 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "addrblock_narrow.h"
+
+#include <daemon.h>
+#include <credentials/certificates/x509.h>
+
+typedef struct private_addrblock_narrow_t private_addrblock_narrow_t;
+
+/**
+ * Private data of an addrblock_narrow_t object.
+ */
+struct private_addrblock_narrow_t {
+
+ /**
+ * Public addrblock_narrow_t interface.
+ */
+ addrblock_narrow_t public;
+};
+
+/**
+ * Check if the negotiated TS list is acceptable by X509 ipAddrBlock constraints
+ */
+static bool check_constraints(ike_sa_t *ike_sa, linked_list_t *list)
+{
+ auth_cfg_t *auth;
+ enumerator_t *auth_enum;
+ certificate_t *cert = NULL;
+
+ auth_enum = ike_sa->create_auth_cfg_enumerator(ike_sa, FALSE);
+ while (auth_enum->enumerate(auth_enum, &auth))
+ {
+ cert = auth->get(auth, AUTH_HELPER_SUBJECT_CERT);
+ if (cert)
+ {
+ break;
+ }
+ }
+ auth_enum->destroy(auth_enum);
+
+ if (cert && cert->get_type(cert) == CERT_X509)
+ {
+ x509_t *x509 = (x509_t*)cert;
+
+ if (x509->get_flags(x509) & X509_IP_ADDR_BLOCKS)
+ {
+ enumerator_t *enumerator, *block_enum;
+ traffic_selector_t *ts, *block_ts;
+
+ DBG1(DBG_IKE, "checking certificate-based traffic selector "
+ "constraints [RFC 3779]");
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &ts))
+ {
+ bool contained = FALSE;
+
+ block_enum = x509->create_ipAddrBlock_enumerator(x509);
+ while (block_enum->enumerate(block_enum, &block_ts))
+ {
+ if (ts->is_contained_in(ts, block_ts))
+ {
+ DBG1(DBG_IKE, " TS %R is contained in address block"
+ " constraint %R", ts, block_ts);
+ contained = TRUE;
+ break;
+ }
+ }
+ block_enum->destroy(block_enum);
+
+ if (!contained)
+ {
+ DBG1(DBG_IKE, " TS %R is not contained in any"
+ " address block constraint", ts);
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Delete all traffic selectors in a list
+ */
+static void flush_ts_list(linked_list_t *list)
+{
+ traffic_selector_t *ts;
+
+ while (list->remove_last(list, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+}
+
+METHOD(listener_t, narrow, bool,
+ private_addrblock_narrow_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ narrow_hook_t type, linked_list_t *local, linked_list_t *remote)
+{
+ switch (type)
+ {
+ case NARROW_RESPONDER:
+ case NARROW_INITIATOR_POST_AUTH:
+ case NARROW_INITIATOR_POST_NOAUTH:
+ if (!check_constraints(ike_sa, remote))
+ {
+ flush_ts_list(local);
+ flush_ts_list(remote);
+ }
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+METHOD(addrblock_narrow_t, destroy, void,
+ private_addrblock_narrow_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+addrblock_narrow_t *addrblock_narrow_create()
+{
+ private_addrblock_narrow_t *this;
+
+ INIT(this,
+ .public = {
+ .listener.narrow = _narrow,
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/addrblock/addrblock_narrow.h b/src/libcharon/plugins/addrblock/addrblock_narrow.h
new file mode 100644
index 000000000..9ab32e671
--- /dev/null
+++ b/src/libcharon/plugins/addrblock/addrblock_narrow.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 addrblock_narrow addrblock_narrow
+ * @{ @ingroup addrblock
+ */
+
+#ifndef ADDRBLOCK_NARROW_H_
+#define ADDRBLOCK_NARROW_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct addrblock_narrow_t addrblock_narrow_t;
+
+/**
+ * Listener that checks traffic selectors against addrblock constraints.
+ */
+struct addrblock_narrow_t {
+
+ /**
+ * Implements listener_t.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a addrblock_narrow_t.
+ */
+ void (*destroy)(addrblock_narrow_t *this);
+};
+
+/**
+ * Create a addrblock_narrow instance.
+ */
+addrblock_narrow_t *addrblock_narrow_create();
+
+#endif /** ADDRBLOCK_NARROW_H_ @}*/
diff --git a/src/libcharon/plugins/addrblock/addrblock_plugin.c b/src/libcharon/plugins/addrblock/addrblock_plugin.c
new file mode 100644
index 000000000..1c407035d
--- /dev/null
+++ b/src/libcharon/plugins/addrblock/addrblock_plugin.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "addrblock_plugin.h"
+
+#include <daemon.h>
+
+#include "addrblock_validator.h"
+#include "addrblock_narrow.h"
+
+typedef struct private_addrblock_plugin_t private_addrblock_plugin_t;
+
+/**
+ * private data of addrblock_plugin
+ */
+struct private_addrblock_plugin_t {
+
+ /**
+ * public functions
+ */
+ addrblock_plugin_t public;
+
+ /**
+ * Validator implementation instance.
+ */
+ addrblock_validator_t *validator;
+
+ /**
+ * Listener to check TS list
+ */
+ addrblock_narrow_t *narrower;
+};
+
+METHOD(plugin_t, destroy, void,
+ private_addrblock_plugin_t *this)
+{
+ charon->bus->remove_listener(charon->bus, &this->narrower->listener);
+ lib->credmgr->remove_validator(lib->credmgr, &this->validator->validator);
+ this->narrower->destroy(this->narrower);
+ this->validator->destroy(this->validator);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *addrblock_plugin_create()
+{
+ private_addrblock_plugin_t *this;
+
+ INIT(this,
+ .public.plugin.destroy = _destroy,
+ .validator = addrblock_validator_create(),
+ .narrower = addrblock_narrow_create(),
+ );
+ lib->credmgr->add_validator(lib->credmgr, &this->validator->validator);
+ charon->bus->add_listener(charon->bus, &this->narrower->listener);
+
+ return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/resolve/resolve_plugin.h b/src/libcharon/plugins/addrblock/addrblock_plugin.h
index 0148b10d7..87bd516f9 100644
--- a/src/libcharon/plugins/resolve/resolve_plugin.h
+++ b/src/libcharon/plugins/addrblock/addrblock_plugin.h
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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
@@ -14,29 +14,29 @@
*/
/**
- * @defgroup resolve resolve
+ * @defgroup addrblock addrblock
* @ingroup cplugins
*
- * @defgroup resolve_plugin resolve_plugin
- * @{ @ingroup resolve
+ * @defgroup addrblock_plugin addrblock_plugin
+ * @{ @ingroup addrblock
*/
-#ifndef RESOLVE_PLUGIN_H_
-#define RESOLVE_PLUGIN_H_
+#ifndef ADDRBLOCK_PLUGIN_H_
+#define ADDRBLOCK_PLUGIN_H_
#include <plugins/plugin.h>
-typedef struct resolve_plugin_t resolve_plugin_t;
+typedef struct addrblock_plugin_t addrblock_plugin_t;
/**
- * Plugin that writes received DNS servers in a resolv.conf file.
+ * RFC 3779 address block checking.
*/
-struct resolve_plugin_t {
+struct addrblock_plugin_t {
/**
- * implements plugin interface
+ * Implements plugin_t. interface.
*/
plugin_t plugin;
};
-#endif /** RESOLVE_PLUGIN_H_ @}*/
+#endif /** ADDRBLOCK_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/addrblock/addrblock_validator.c b/src/libcharon/plugins/addrblock/addrblock_validator.c
new file mode 100644
index 000000000..44ef38d85
--- /dev/null
+++ b/src/libcharon/plugins/addrblock/addrblock_validator.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ * Copyright (C) 2009 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "addrblock_validator.h"
+
+#include <debug.h>
+#include <credentials/certificates/x509.h>
+#include <selectors/traffic_selector.h>
+
+typedef struct private_addrblock_validator_t private_addrblock_validator_t;
+
+/**
+ * Private data of an addrblock_validator_t object.
+ */
+struct private_addrblock_validator_t {
+
+ /**
+ * Public addrblock_validator_t interface.
+ */
+ addrblock_validator_t public;
+};
+
+/**
+ * Do the addrblock check for two x509 plugins
+ */
+static bool check_addrblock(x509_t *subject, x509_t *issuer)
+{
+ bool subject_const, issuer_const, contained = TRUE;
+ enumerator_t *subject_enumerator, *issuer_enumerator;
+ traffic_selector_t *subject_ts, *issuer_ts;
+
+ subject_const = subject->get_flags(subject) & X509_IP_ADDR_BLOCKS;
+ issuer_const = issuer->get_flags(issuer) & X509_IP_ADDR_BLOCKS;
+
+ if (!subject_const && !issuer_const)
+ {
+ return TRUE;
+ }
+ if (!subject_const)
+ {
+ DBG1(DBG_CFG, "subject certficate lacks ipAddrBlocks extension");
+ return FALSE;
+ }
+ if (!issuer_const)
+ {
+ DBG1(DBG_CFG, "issuer certficate lacks ipAddrBlocks extension");
+ return FALSE;
+ }
+ subject_enumerator = subject->create_ipAddrBlock_enumerator(subject);
+ while (subject_enumerator->enumerate(subject_enumerator, &subject_ts))
+ {
+ contained = FALSE;
+
+ issuer_enumerator = issuer->create_ipAddrBlock_enumerator(issuer);
+ while (issuer_enumerator->enumerate(issuer_enumerator, &issuer_ts))
+ {
+ if (subject_ts->is_contained_in(subject_ts, issuer_ts))
+ {
+ DBG2(DBG_CFG, " subject address block %R is contained in "
+ "issuer address block %R", subject_ts, issuer_ts);
+ contained = TRUE;
+ break;
+ }
+ }
+ issuer_enumerator->destroy(issuer_enumerator);
+ if (!contained)
+ {
+ DBG1(DBG_CFG, "subject address block %R is not contained in any "
+ "issuer address block", subject_ts);
+ break;
+ }
+ }
+ subject_enumerator->destroy(subject_enumerator);
+ return contained;
+}
+
+METHOD(cert_validator_t, validate, bool,
+ private_addrblock_validator_t *this, certificate_t *subject,
+ certificate_t *issuer, bool online, int pathlen, auth_cfg_t *auth)
+{
+ if (subject->get_type(subject) == CERT_X509 &&
+ issuer->get_type(issuer) == CERT_X509)
+ {
+ return check_addrblock((x509_t*)subject, (x509_t*)issuer);
+ }
+ return TRUE;
+}
+
+METHOD(addrblock_validator_t, destroy, void,
+ private_addrblock_validator_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+addrblock_validator_t *addrblock_validator_create()
+{
+ private_addrblock_validator_t *this;
+
+ INIT(this,
+ .public = {
+ .validator.validate = _validate,
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/addrblock/addrblock_validator.h b/src/libcharon/plugins/addrblock/addrblock_validator.h
new file mode 100644
index 000000000..423f0d41a
--- /dev/null
+++ b/src/libcharon/plugins/addrblock/addrblock_validator.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 addrblock_validator addrblock_validator
+ * @{ @ingroup addrblock
+ */
+
+#ifndef ADDRBLOCK_VALIDATOR_H_
+#define ADDRBLOCK_VALIDATOR_H_
+
+#include <credentials/cert_validator.h>
+
+typedef struct addrblock_validator_t addrblock_validator_t;
+
+/**
+ * RFC 3779 address block X509 certificate validator.
+ */
+struct addrblock_validator_t {
+
+ /**
+ * Implements cert_validator_t interface.
+ */
+ cert_validator_t validator;
+
+ /**
+ * Destroy a addrblock_validator_t.
+ */
+ void (*destroy)(addrblock_validator_t *this);
+};
+
+/**
+ * Create a addrblock_validator instance.
+ */
+addrblock_validator_t *addrblock_validator_create();
+
+#endif /** ADDRBLOCK_VALIDATOR_H_ @}*/
diff --git a/src/libcharon/plugins/android/Makefile.am b/src/libcharon/plugins/android/Makefile.am
index e8423589c..b922ef4af 100644
--- a/src/libcharon/plugins/android/Makefile.am
+++ b/src/libcharon/plugins/android/Makefile.am
@@ -12,7 +12,10 @@ endif
libstrongswan_android_la_SOURCES = \
android_plugin.c android_plugin.h \
- android_handler.c android_handler.h
+ android_service.c android_service.h \
+ android_handler.c android_handler.h \
+ android_logger.c android_logger.h \
+ android_creds.c android_creds.h
libstrongswan_android_la_LDFLAGS = -module -avoid-version
libstrongswan_android_la_LIBADD = -lcutils
diff --git a/src/libcharon/plugins/android/Makefile.in b/src/libcharon/plugins/android/Makefile.in
index 9f12a9c75..6e4903ee1 100644
--- a/src/libcharon/plugins/android/Makefile.in
+++ b/src/libcharon/plugins/android/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -75,7 +75,8 @@ am__installdirs = "$(DESTDIR)$(plugindir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
libstrongswan_android_la_DEPENDENCIES =
am_libstrongswan_android_la_OBJECTS = android_plugin.lo \
- android_handler.lo
+ android_service.lo android_handler.lo android_logger.lo \
+ android_creds.lo
libstrongswan_android_la_OBJECTS = \
$(am_libstrongswan_android_la_OBJECTS)
libstrongswan_android_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -265,7 +266,10 @@ AM_CFLAGS = -rdynamic
@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-android.la
libstrongswan_android_la_SOURCES = \
android_plugin.c android_plugin.h \
- android_handler.c android_handler.h
+ android_service.c android_service.h \
+ android_handler.c android_handler.h \
+ android_logger.c android_logger.h \
+ android_creds.c android_creds.h
libstrongswan_android_la_LDFLAGS = -module -avoid-version
libstrongswan_android_la_LIBADD = -lcutils
@@ -352,8 +356,11 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_creds.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_handler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_logger.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_service.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/src/libcharon/plugins/android/android_creds.c b/src/libcharon/plugins/android/android_creds.c
new file mode 100644
index 000000000..aa7fc6f92
--- /dev/null
+++ b/src/libcharon/plugins/android/android_creds.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <keystore_get.h>
+
+#include "android_creds.h"
+
+#include <daemon.h>
+#include <threading/rwlock.h>
+
+typedef struct private_android_creds_t private_android_creds_t;
+
+/**
+ * Private data of an android_creds_t object
+ */
+struct private_android_creds_t {
+
+ /**
+ * Public interface
+ */
+ android_creds_t public;
+
+ /**
+ * List of trusted certificates, certificate_t*
+ */
+ linked_list_t *certs;
+
+ /**
+ * User name (ID)
+ */
+ identification_t *user;
+
+ /**
+ * User password
+ */
+ char *pass;
+
+ /**
+ * read/write lock
+ */
+ rwlock_t *lock;
+
+};
+
+/**
+ * Certificate enumerator data
+ */
+typedef struct {
+ private_android_creds_t *this;
+ key_type_t key;
+ identification_t *id;
+} cert_data_t;
+
+/**
+ * Filter function for certificates enumerator
+ */
+static bool cert_filter(cert_data_t *data, certificate_t **in,
+ certificate_t **out)
+{
+ certificate_t *cert = *in;
+ public_key_t *public;
+
+ public = cert->get_public_key(cert);
+ if (!public)
+ {
+ return FALSE;
+ }
+ if (data->key != KEY_ANY && public->get_type(public) != data->key)
+ {
+ public->destroy(public);
+ return FALSE;
+ }
+ if (data->id && data->id->get_type(data->id) == ID_KEY_ID &&
+ public->has_fingerprint(public, data->id->get_encoding(data->id)))
+ {
+ public->destroy(public);
+ *out = cert;
+ return TRUE;
+ }
+ public->destroy(public);
+ if (data->id && !cert->has_subject(cert, data->id))
+ {
+ return FALSE;
+ }
+ *out = cert;
+ return TRUE;
+}
+
+/**
+ * Destroy certificate enumerator data
+ */
+static void cert_data_destroy(cert_data_t *this)
+{
+ this->this->lock->unlock(this->this->lock);
+ free(this);
+}
+
+METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
+ private_android_creds_t *this, certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted)
+{
+ if (cert == CERT_X509 || cert == CERT_ANY)
+ {
+ cert_data_t *data;
+ this->lock->read_lock(this->lock);
+ INIT(data, .this = this, .id = id, .key = key);
+ return enumerator_create_filter(
+ this->certs->create_enumerator(this->certs),
+ (void*)cert_filter, data, (void*)cert_data_destroy);
+ }
+ return NULL;
+}
+
+/**
+ * Shared key enumerator implementation
+ */
+typedef struct {
+ enumerator_t public;
+ private_android_creds_t *this;
+ shared_key_t *key;
+ bool done;
+} shared_enumerator_t;
+
+METHOD(enumerator_t, shared_enumerate, bool,
+ shared_enumerator_t *this, shared_key_t **key, id_match_t *me,
+ id_match_t *other)
+{
+ if (this->done)
+ {
+ return FALSE;
+ }
+ *key = this->key;
+ *me = ID_MATCH_PERFECT;
+ *other = ID_MATCH_ANY;
+ this->done = TRUE;
+ return TRUE;
+}
+
+METHOD(enumerator_t, shared_destroy, void,
+ shared_enumerator_t *this)
+{
+ this->key->destroy(this->key);
+ this->this->lock->unlock(this->this->lock);
+ free(this);
+}
+
+METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
+ private_android_creds_t *this, shared_key_type_t type,
+ identification_t *me, identification_t *other)
+{
+ shared_enumerator_t *enumerator;
+
+ this->lock->read_lock(this->lock);
+
+ if (!this->user || !this->pass)
+ {
+ this->lock->unlock(this->lock);
+ return NULL;
+ }
+ if (type != SHARED_EAP && type != SHARED_IKE)
+ {
+ this->lock->unlock(this->lock);
+ return NULL;
+ }
+ if (me && !me->equals(me, this->user))
+ {
+ this->lock->unlock(this->lock);
+ return NULL;
+ }
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_shared_enumerate,
+ .destroy = _shared_destroy,
+ },
+ .this = this,
+ .done = FALSE,
+ .key = shared_key_create(type, chunk_clone(chunk_create(this->pass,
+ strlen(this->pass)))),
+ );
+ return &enumerator->public;
+}
+
+METHOD(android_creds_t, add_certificate, bool,
+ private_android_creds_t *this, char *name)
+{
+ certificate_t *cert = NULL;
+ bool status = FALSE;
+ chunk_t chunk;
+#ifdef KEYSTORE_MESSAGE_SIZE
+ /* most current interface, the eclair interface (without key length) is
+ * currently not supported */
+ char value[KEYSTORE_MESSAGE_SIZE];
+ chunk.ptr = value;
+ chunk.len = keystore_get(name, strlen(name), chunk.ptr);
+ if (chunk.len > 0)
+#else
+ /* 1.6 interface, allocates memory */
+ chunk.ptr = keystore_get(name, &chunk.len);
+ if (chunk.ptr)
+#endif /* KEYSTORE_MESSAGE_SIZE */
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_BLOB_PEM, chunk, BUILD_END);
+ if (cert)
+ {
+ this->lock->write_lock(this->lock);
+ this->certs->insert_last(this->certs, cert);
+ this->lock->unlock(this->lock);
+ status = TRUE;
+ }
+#ifndef KEYSTORE_MESSAGE_SIZE
+ free(chunk.ptr);
+#endif /* KEYSTORE_MESSAGE_SIZE */
+ }
+ return status;
+}
+
+METHOD(android_creds_t, set_username_password, void,
+ private_android_creds_t *this, identification_t *id, char *password)
+{
+ this->lock->write_lock(this->lock);
+ DESTROY_IF(this->user);
+ this->user = id->clone(id);
+ free(this->pass);
+ this->pass = password ? strdup(password) : NULL;
+ this->lock->unlock(this->lock);
+}
+
+METHOD(android_creds_t, clear, void,
+ private_android_creds_t *this)
+{
+ certificate_t *cert;
+ this->lock->write_lock(this->lock);
+ while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS)
+ {
+ cert->destroy(cert);
+ }
+ DESTROY_IF(this->user);
+ free(this->pass);
+ this->user = NULL;
+ this->pass = NULL;
+ this->lock->unlock(this->lock);
+}
+
+METHOD(android_creds_t, destroy, void,
+ private_android_creds_t *this)
+{
+ clear(this);
+ this->certs->destroy(this->certs);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+android_creds_t *android_creds_create()
+{
+ private_android_creds_t *this;
+
+ INIT(this,
+ .public = {
+ .set = {
+ .create_cert_enumerator = _create_cert_enumerator,
+ .create_shared_enumerator = _create_shared_enumerator,
+ .create_private_enumerator = (void*)return_null,
+ .create_cdp_enumerator = (void*)return_null,
+ .cache_cert = (void*)nop,
+ },
+ .add_certificate = _add_certificate,
+ .set_username_password = _set_username_password,
+ .clear = _clear,
+ .destroy = _destroy,
+ },
+ .certs = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libcharon/plugins/android/android_creds.h b/src/libcharon/plugins/android/android_creds.h
new file mode 100644
index 000000000..0f7b8e0ea
--- /dev/null
+++ b/src/libcharon/plugins/android/android_creds.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup android_creds android_creds
+ * @{ @ingroup android
+ */
+
+#ifndef ANDROID_CREDS_H_
+#define ANDROID_CREDS_H_
+
+#include <credentials/credential_set.h>
+
+typedef struct android_creds_t android_creds_t;
+
+/**
+ * Android credentials helper.
+ */
+struct android_creds_t {
+
+ /**
+ * Implements credential_set_t
+ */
+ credential_set_t set;
+
+ /**
+ * Add a trusted CA certificate from the Android keystore to serve by
+ * this set.
+ *
+ * @param name name/ID of the certificate in the keystore
+ * @return FALSE if the certificate does not exist or is invalid
+ */
+ bool (*add_certificate)(android_creds_t *this, char *name);
+
+ /**
+ * Set the username and password for authentication.
+ *
+ * @param id ID of the user
+ * @param password password to use for authentication
+ */
+ void (*set_username_password)(android_creds_t *this, identification_t *id,
+ char *password);
+
+ /**
+ * Clear the stored credentials.
+ */
+ void (*clear)(android_creds_t *this);
+
+ /**
+ * Destroy a android_creds instance.
+ */
+ void (*destroy)(android_creds_t *this);
+
+};
+
+/**
+ * Create an android_creds instance.
+ */
+android_creds_t *android_creds_create();
+
+#endif /** ANDROID_CREDS_H_ @}*/
diff --git a/src/libcharon/plugins/android/android_handler.c b/src/libcharon/plugins/android/android_handler.c
index a475eeaab..ec3ff7a51 100644
--- a/src/libcharon/plugins/android/android_handler.c
+++ b/src/libcharon/plugins/android/android_handler.c
@@ -75,7 +75,7 @@ host_t *get_dns_server(int index)
host_t *dns = NULL;
char key[10], value[PROPERTY_VALUE_MAX];
- if (snprintf(key, sizeof(key), "net.dns%d", index) >= sizeof(key))
+ if (snprintf(key, sizeof(key), "vpn.dns%d", index) >= sizeof(key))
{
return NULL;
}
@@ -94,7 +94,7 @@ bool set_dns_server(int index, host_t *dns)
{
char key[10], value[PROPERTY_VALUE_MAX];
- if (snprintf(key, sizeof(key), "net.dns%d", index) >= sizeof(key))
+ if (snprintf(key, sizeof(key), "vpn.dns%d", index) >= sizeof(key))
{
return FALSE;
}
diff --git a/src/libcharon/plugins/android/android_logger.c b/src/libcharon/plugins/android/android_logger.c
new file mode 100644
index 000000000..43c56e656
--- /dev/null
+++ b/src/libcharon/plugins/android/android_logger.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+#include <android/log.h>
+
+#include "android_logger.h"
+
+#include <library.h>
+#include <daemon.h>
+
+typedef struct private_android_logger_t private_android_logger_t;
+
+/**
+ * Private data of an android_logger_t object
+ */
+struct private_android_logger_t {
+
+ /**
+ * Public interface
+ */
+ android_logger_t public;
+
+ /**
+ * logging level
+ */
+ int level;
+
+};
+
+
+METHOD(listener_t, log_, bool,
+ private_android_logger_t *this, debug_t group, level_t level,
+ int thread, ike_sa_t* ike_sa, char *format, va_list args)
+{
+ if (level <= this->level)
+ {
+ char sgroup[16], buffer[8192];
+ char *current = buffer, *next;
+ snprintf(sgroup, sizeof(sgroup), "%N", debug_names, group);
+ vsnprintf(buffer, sizeof(buffer), format, args);
+ while (current)
+ { /* log each line seperately */
+ next = strchr(current, '\n');
+ if (next)
+ {
+ *(next++) = '\0';
+ }
+ __android_log_print(ANDROID_LOG_INFO, "charon", "%.2d[%s] %s\n",
+ thread, sgroup, current);
+ current = next;
+ }
+ }
+ /* always stay registered */
+ return TRUE;
+}
+
+METHOD(android_logger_t, destroy, void,
+ private_android_logger_t *this)
+{
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+android_logger_t *android_logger_create()
+{
+ private_android_logger_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .log = _log_,
+ },
+ .destroy = _destroy,
+ },
+ .level = lib->settings->get_int(lib->settings,
+ "charon.plugins.android.loglevel", 1),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libcharon/plugins/resolve/resolve_handler.h b/src/libcharon/plugins/android/android_logger.h
index 77bf9781c..c6fe5aff3 100644
--- a/src/libcharon/plugins/resolve/resolve_handler.h
+++ b/src/libcharon/plugins/android/android_logger.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Martin Willi
+ * Copyright (C) 2010 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -14,36 +14,39 @@
*/
/**
- * @defgroup resolve_handler resolve_handler
- * @{ @ingroup resolve
+ * @defgroup android_logger android_logger
+ * @{ @ingroup android
*/
-#ifndef RESOLVE_HANDLER_H_
-#define RESOLVE_HANDLER_H_
+#ifndef ANDROID_LOGGER_H_
+#define ANDROID_LOGGER_H_
-#include <attributes/attribute_handler.h>
+#include <bus/bus.h>
-typedef struct resolve_handler_t resolve_handler_t;
+typedef struct android_logger_t android_logger_t;
/**
- * Handle DNS configuration attributes by mangling a resolv.conf file.
+ * Android specific logger.
*/
-struct resolve_handler_t {
+struct android_logger_t {
/**
- * Implements the attribute_handler_t interface
+ * Implements bus_listener_t interface
*/
- attribute_handler_t handler;
+ listener_t listener;
/**
- * Destroy a resolve_handler_t.
+ * Destroy the logger.
*/
- void (*destroy)(resolve_handler_t *this);
+ void (*destroy)(android_logger_t *this);
+
};
/**
- * Create a resolve_handler instance.
+ * Create an Android specific logger instance.
+ *
+ * @return logger instance
*/
-resolve_handler_t *resolve_handler_create();
+android_logger_t *android_logger_create();
-#endif /** RESOLVE_HANDLER_H_ @}*/
+#endif /** ANDROID_LOGGER_H_ @}*/
diff --git a/src/libcharon/plugins/android/android_plugin.c b/src/libcharon/plugins/android/android_plugin.c
index 9a558f53b..e2c8572ef 100644
--- a/src/libcharon/plugins/android/android_plugin.c
+++ b/src/libcharon/plugins/android/android_plugin.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2010 Tobias Brunner
* Copyright (C) 2010 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -14,7 +15,10 @@
*/
#include "android_plugin.h"
+#include "android_logger.h"
#include "android_handler.h"
+#include "android_creds.h"
+#include "android_service.h"
#include <hydra.h>
#include <daemon.h>
@@ -32,16 +36,38 @@ struct private_android_plugin_t {
android_plugin_t public;
/**
+ * Android specific logger
+ */
+ android_logger_t *logger;
+
+ /**
* Android specific DNS handler
*/
android_handler_t *handler;
+
+ /**
+ * Android specific credential set
+ */
+ android_creds_t *creds;
+
+ /**
+ * Service that interacts with the Android Settings frontend
+ */
+ android_service_t *service;
+
};
METHOD(plugin_t, destroy, void,
- private_android_plugin_t *this)
+ private_android_plugin_t *this)
{
- hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler);
+ hydra->attributes->remove_handler(hydra->attributes,
+ &this->handler->handler);
+ lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
+ charon->bus->remove_listener(charon->bus, &this->logger->listener);
+ this->creds->destroy(this->creds);
this->handler->destroy(this->handler);
+ this->logger->destroy(this->logger);
+ DESTROY_IF(this->service);
free(this);
}
@@ -56,11 +82,22 @@ plugin_t *android_plugin_create()
.public.plugin = {
.destroy = _destroy,
},
+ .logger = android_logger_create(),
.handler = android_handler_create(),
+ .creds = android_creds_create(),
);
+ charon->bus->add_listener(charon->bus, &this->logger->listener);
+ lib->credmgr->add_set(lib->credmgr, &this->creds->set);
hydra->attributes->add_handler(hydra->attributes, &this->handler->handler);
+ this->service = android_service_create(this->creds);
+ if (!this->service)
+ {
+ destroy(this);
+ return NULL;
+ }
+
return &this->public.plugin;
}
diff --git a/src/libcharon/plugins/android/android_service.c b/src/libcharon/plugins/android/android_service.c
new file mode 100644
index 000000000..538c4a9a2
--- /dev/null
+++ b/src/libcharon/plugins/android/android_service.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <unistd.h>
+#include <cutils/sockets.h>
+#include <cutils/properties.h>
+#include <signal.h>
+
+#include "android_service.h"
+
+#include <daemon.h>
+#include <threading/thread.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_android_service_t private_android_service_t;
+
+/**
+ * private data of Android service
+ */
+struct private_android_service_t {
+
+ /**
+ * public interface
+ */
+ android_service_t public;
+
+ /**
+ * current IKE_SA
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * job that handles requests from the Android control socket
+ */
+ callback_job_t *job;
+
+ /**
+ * android credentials
+ */
+ android_creds_t *creds;
+
+ /**
+ * android control socket
+ */
+ int control;
+
+};
+
+/**
+ * Some of the error codes defined in VpnManager.java
+ */
+typedef enum {
+ /** Error code to indicate an error from authentication. */
+ VPN_ERROR_AUTH = 51,
+ /** Error code to indicate the connection attempt failed. */
+ VPN_ERROR_CONNECTION_FAILED = 101,
+ /** Error code to indicate an error of remote server hanging up. */
+ VPN_ERROR_REMOTE_HUNG_UP = 7,
+ /** Error code to indicate an error of losing connectivity. */
+ VPN_ERROR_CONNECTION_LOST = 103,
+} android_vpn_errors_t;
+
+/**
+ * send a status code back to the Android app
+ */
+static void send_status(private_android_service_t *this, u_char code)
+{
+ DBG1(DBG_CFG, "status of Android plugin changed: %d", code);
+ send(this->control, &code, 1, 0);
+}
+
+METHOD(listener_t, ike_updown, bool,
+ private_android_service_t *this, ike_sa_t *ike_sa, bool up)
+{
+ /* this callback is only registered during initiation, so if the IKE_SA
+ * goes down we assume an authentication error */
+ if (this->ike_sa == ike_sa && !up)
+ {
+ send_status(this, VPN_ERROR_AUTH);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, child_state_change, bool,
+ private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ child_sa_state_t state)
+{
+ /* this callback is only registered during initiation, so we still have
+ * the control socket open */
+ if (this->ike_sa == ike_sa && state == CHILD_DESTROYING)
+ {
+ send_status(this, VPN_ERROR_CONNECTION_FAILED);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Callback used to shutdown the daemon
+ */
+static job_requeue_t shutdown_callback(void *data)
+{
+ kill(0, SIGTERM);
+ return JOB_REQUEUE_NONE;
+}
+
+METHOD(listener_t, child_updown, bool,
+ private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ bool up)
+{
+ if (this->ike_sa == ike_sa)
+ {
+ if (up)
+ {
+ /* disable the hooks registered to catch initiation failures */
+ this->public.listener.ike_updown = NULL;
+ this->public.listener.child_state_change = NULL;
+ property_set("vpn.status", "ok");
+ }
+ else
+ {
+ callback_job_t *job;
+ /* the control socket is closed as soon as vpn.status is set to "ok"
+ * and the daemon proxy then only checks for terminated daemons to
+ * detect lost connections, so... */
+ DBG1(DBG_CFG, "connection lost, raising delayed SIGTERM");
+ /* to avoid any conflicts we send the SIGTERM not directly from this
+ * callback, but from a different thread. we also delay it to avoid
+ * a race condition during a regular shutdown */
+ job = callback_job_create(shutdown_callback, NULL, NULL, NULL);
+ charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, 1);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_rekey, bool,
+ private_android_service_t *this, ike_sa_t *old, ike_sa_t *new)
+{
+ if (this->ike_sa == old)
+ {
+ this->ike_sa = new;
+ }
+ return TRUE;
+}
+
+/**
+ * Read a string argument from the Android control socket
+ */
+static char *read_argument(int fd, u_char length)
+{
+ int offset = 0;
+ char *data = malloc(length + 1);
+ while (offset < length)
+ {
+ int n = recv(fd, &data[offset], length - offset, 0);
+ if (n < 0)
+ {
+ DBG1(DBG_CFG, "failed to read argument from Android"
+ " control socket: %s", strerror(errno));
+ free(data);
+ return NULL;
+ }
+ offset += n;
+ }
+ data[length] = '\0';
+ DBG3(DBG_CFG, "received argument from Android control socket: %s", data);
+ return data;
+}
+
+/**
+ * handle the request received from the Android control socket
+ */
+static job_requeue_t initiate(private_android_service_t *this)
+{
+ bool oldstate;
+ int fd, i = 0;
+ char *hostname = NULL, *cacert = NULL, *username = NULL, *password = NULL;
+ identification_t *gateway = NULL, *user = NULL;
+ ike_cfg_t *ike_cfg;
+ peer_cfg_t *peer_cfg;
+ child_cfg_t *child_cfg;
+ traffic_selector_t *ts;
+ ike_sa_t *ike_sa;
+ auth_cfg_t *auth;
+ lifetime_cfg_t lifetime = {
+ .time = {
+ .life = 10800, /* 3h */
+ .rekey = 10200, /* 2h50min */
+ .jitter = 300 /* 5min */
+ }
+ };
+
+ fd = accept(this->control, NULL, 0);
+ if (fd < 0)
+ {
+ DBG1(DBG_CFG, "accept on Android control socket failed: %s",
+ strerror(errno));
+ return JOB_REQUEUE_NONE;
+ }
+ /* the original control socket is not used anymore */
+ close(this->control);
+ this->control = fd;
+
+ while (TRUE)
+ {
+ u_char length;
+ if (recv(fd, &length, 1, 0) != 1)
+ {
+ DBG1(DBG_CFG, "failed to read from Android control socket: %s",
+ strerror(errno));
+ return JOB_REQUEUE_NONE;
+ }
+
+ if (length == 0xFF)
+ { /* last argument */
+ break;
+ }
+ else
+ {
+ switch (i++)
+ {
+ case 0: /* gateway */
+ hostname = read_argument(fd, length);
+ break;
+ case 1: /* CA certificate name */
+ cacert = read_argument(fd, length);
+ break;
+ case 2: /* username */
+ username = read_argument(fd, length);
+ break;
+ case 3: /* password */
+ password = read_argument(fd, length);
+ break;
+ }
+ }
+ }
+
+ if (cacert)
+ {
+ if (!this->creds->add_certificate(this->creds, cacert))
+ {
+ DBG1(DBG_CFG, "failed to load CA certificate");
+ }
+ /* if this is a server cert we could use the cert subject as id
+ * but we have to test first if that possible to configure */
+ }
+
+ gateway = identification_create_from_string(hostname);
+ DBG1(DBG_CFG, "using CA certificate, gateway identitiy '%Y'", gateway);
+
+ if (username)
+ {
+ user = identification_create_from_string(username);
+ this->creds->set_username_password(this->creds, user, password);
+ }
+
+ ike_cfg = ike_cfg_create(TRUE, FALSE, "0.0.0.0", IKEV2_UDP_PORT,
+ hostname, IKEV2_UDP_PORT);
+ ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
+
+ peer_cfg = peer_cfg_create("android", 2, ike_cfg, CERT_SEND_IF_ASKED,
+ UNIQUE_REPLACE, 1, /* keyingtries */
+ 36000, 0, /* rekey 10h, reauth none */
+ 600, 600, /* jitter, over 10min */
+ TRUE, 0, /* mobike, DPD */
+ host_create_from_string("0.0.0.0", 0) /* virt */,
+ NULL, FALSE, NULL, NULL); /* pool, mediation */
+
+ auth = auth_cfg_create();
+ auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
+ auth->add(auth, AUTH_RULE_IDENTITY, user);
+ peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
+ auth = auth_cfg_create();
+ auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
+ auth->add(auth, AUTH_RULE_IDENTITY, gateway);
+ peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
+
+ child_cfg = child_cfg_create("android", &lifetime, NULL, TRUE, MODE_TUNNEL,
+ ACTION_NONE, ACTION_NONE, FALSE, 0, 0,
+ NULL, NULL);
+ child_cfg->add_proposal(child_cfg, proposal_create_default(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",
+ 0, "255.255.255.255", 65535);
+ child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+ peer_cfg->add_child_cfg(peer_cfg, child_cfg);
+ /* get an additional reference because initiate consumes one */
+ child_cfg->get_ref(child_cfg);
+
+ /* get us an IKE_SA */
+ ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
+ peer_cfg);
+ if (!ike_sa->get_peer_cfg(ike_sa))
+ {
+ ike_sa->set_peer_cfg(ike_sa, peer_cfg);
+ }
+ peer_cfg->destroy(peer_cfg);
+
+ /* store the IKE_SA so we can track its progress */
+ this->ike_sa = ike_sa;
+
+ /* confirm that we received the request */
+ send_status(this, i);
+
+ if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
+ {
+ DBG1(DBG_CFG, "failed to initiate tunnel");
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ ike_sa);
+ send_status(this, VPN_ERROR_CONNECTION_FAILED);
+ return JOB_REQUEUE_NONE;
+ }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return JOB_REQUEUE_NONE;
+}
+
+METHOD(android_service_t, destroy, void,
+ private_android_service_t *this)
+{
+ charon->bus->remove_listener(charon->bus, &this->public.listener);
+ close(this->control);
+ free(this);
+}
+
+/**
+ * See header
+ */
+android_service_t *android_service_create(android_creds_t *creds)
+{
+ private_android_service_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .ike_updown = _ike_updown,
+ .child_state_change = _child_state_change,
+ .child_updown = _child_updown,
+ .ike_rekey = _ike_rekey,
+ },
+ .destroy = _destroy,
+ },
+ .creds = creds,
+ );
+
+ this->control = android_get_control_socket("charon");
+ if (this->control == -1)
+ {
+ DBG1(DBG_CFG, "failed to get Android control socket");
+ free(this);
+ return NULL;
+ }
+
+ if (listen(this->control, 1) < 0)
+ {
+ DBG1(DBG_CFG, "failed to listen on Android control socket: %s",
+ strerror(errno));
+ close(this->control);
+ free(this);
+ return NULL;
+ }
+
+ charon->bus->add_listener(charon->bus, &this->public.listener);
+ this->job = callback_job_create((callback_job_cb_t)initiate, this,
+ NULL, NULL);
+ charon->processor->queue_job(charon->processor, (job_t*)this->job);
+
+ return &this->public;
+}
+
diff --git a/src/libcharon/plugins/android/android_service.h b/src/libcharon/plugins/android/android_service.h
new file mode 100644
index 000000000..d096d6cd5
--- /dev/null
+++ b/src/libcharon/plugins/android/android_service.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup android_service android_service
+ * @{ @ingroup android
+ */
+
+#ifndef ANDROID_SERVICE_H_
+#define ANDROID_SERVICE_H_
+
+typedef struct android_service_t android_service_t;
+
+#include <bus/listeners/listener.h>
+
+#include "android_creds.h"
+
+/**
+ * Service that interacts with the Android Settings frontend.
+ */
+struct android_service_t {
+
+ /**
+ * Implements listener_t.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a android_service_t.
+ */
+ void (*destroy)(android_service_t *this);
+
+};
+
+/**
+ * Create an Android service instance.
+ *
+ * @param creds Android credentials
+ */
+android_service_t *android_service_create(android_creds_t *creds);
+
+#endif /** ANDROID_SERVICE_H_ @}*/
diff --git a/src/libcharon/plugins/dhcp/Makefile.in b/src/libcharon/plugins/dhcp/Makefile.in
index 7606b963c..b34654fb7 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/dhcp/dhcp_provider.c b/src/libcharon/plugins/dhcp/dhcp_provider.c
index dbcceb6ce..a6a887780 100644
--- a/src/libcharon/plugins/dhcp/dhcp_provider.c
+++ b/src/libcharon/plugins/dhcp/dhcp_provider.c
@@ -129,7 +129,8 @@ METHOD(attribute_provider_t, release_address, bool,
}
METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
- private_dhcp_provider_t *this, identification_t *id, host_t *vip)
+ private_dhcp_provider_t *this, char *pool, identification_t *id,
+ host_t *vip)
{
dhcp_transaction_t *transaction;
diff --git a/src/libcharon/plugins/eap_aka/Makefile.in b/src/libcharon/plugins/eap_aka/Makefile.in
index 1cea81a9b..14bf3f15d 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_aka/eap_aka_peer.c b/src/libcharon/plugins/eap_aka/eap_aka_peer.c
index 26546809d..dfcc69710 100644
--- a/src/libcharon/plugins/eap_aka/eap_aka_peer.c
+++ b/src/libcharon/plugins/eap_aka/eap_aka_peer.c
@@ -421,7 +421,6 @@ static status_t process_notification(private_eap_aka_peer_t *this,
/* test success bit */
if (!(data.ptr[0] & 0x80))
{
- success = FALSE;
DBG1(DBG_IKE, "received EAP-AKA notification error '%N'",
simaka_notification_names, code);
}
diff --git a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in
index d0b0f5601..b41b59616 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c
index 9817fff8f..a9767ad91 100644
--- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c
+++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c
@@ -52,8 +52,7 @@ bool eap_aka_3gpp2_get_k(identification_t *id, char k[AKA_K_LEN])
shared_key_t *shared;
chunk_t key;
- shared = charon->credentials->get_shared(charon->credentials,
- SHARED_EAP, id, NULL);
+ shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, id, NULL);
if (shared == NULL)
{
return FALSE;
diff --git a/src/libcharon/plugins/eap_gtc/Makefile.in b/src/libcharon/plugins/eap_gtc/Makefile.in
index 110e1528b..57952f621 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_gtc/eap_gtc.c b/src/libcharon/plugins/eap_gtc/eap_gtc.c
index c7f55fa70..f641ad13a 100644
--- a/src/libcharon/plugins/eap_gtc/eap_gtc.c
+++ b/src/libcharon/plugins/eap_gtc/eap_gtc.c
@@ -168,8 +168,8 @@ static status_t process_peer(private_eap_gtc_t *this,
chunk_t key;
size_t len;
- shared = charon->credentials->get_shared(charon->credentials, SHARED_EAP,
- this->peer, this->server);
+ shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP,
+ this->peer, this->server);
if (shared == NULL)
{
DBG1(DBG_IKE, "no EAP key found for '%Y' - '%Y'",
diff --git a/src/libcharon/plugins/eap_identity/Makefile.in b/src/libcharon/plugins/eap_identity/Makefile.in
index bbb987dd6..d78957438 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_md5/Makefile.in b/src/libcharon/plugins/eap_md5/Makefile.in
index 943811604..5bfc59fa4 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_md5/eap_md5.c b/src/libcharon/plugins/eap_md5/eap_md5.c
index 0eda8f755..3554ae12e 100644
--- a/src/libcharon/plugins/eap_md5/eap_md5.c
+++ b/src/libcharon/plugins/eap_md5/eap_md5.c
@@ -85,8 +85,7 @@ static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response,
chunk_t concat;
hasher_t *hasher;
- shared = charon->credentials->get_shared(charon->credentials, SHARED_EAP,
- me, other);
+ shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, me, other);
if (shared == NULL)
{
DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'", me, other);
diff --git a/src/libcharon/plugins/eap_mschapv2/Makefile.in b/src/libcharon/plugins/eap_mschapv2/Makefile.in
index 2f6c65df4..d61cc9e5d 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
index c1ccf72eb..3cd8d994c 100644
--- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
+++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
@@ -614,8 +614,7 @@ static bool get_nt_hash(private_eap_mschapv2_t *this, identification_t *me,
chunk_t password;
/* try to find a stored NT_HASH first */
- shared = charon->credentials->get_shared(charon->credentials,
- SHARED_NT_HASH, me, other);
+ shared = lib->credmgr->get_shared(lib->credmgr, SHARED_NT_HASH, me, other);
if (shared )
{
*nt_hash = chunk_clone(shared->get_key(shared));
@@ -624,8 +623,7 @@ static bool get_nt_hash(private_eap_mschapv2_t *this, identification_t *me,
}
/* fallback to plaintext password */
- shared = charon->credentials->get_shared(charon->credentials,
- SHARED_EAP, me, other);
+ shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, me, other);
if (shared)
{
password = ascii_to_unicode(shared->get_key(shared));
@@ -820,7 +818,7 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
eap_mschapv2_header_t *eap;
chunk_t data;
char *message, *token, *msg = NULL;
- int message_len, error, retryable;
+ int message_len, error = 0, retryable;
chunk_t challenge = chunk_empty;
data = in->get_data(in);
diff --git a/src/libcharon/plugins/eap_radius/Makefile.am b/src/libcharon/plugins/eap_radius/Makefile.am
index a3abd4124..afc50bced 100644
--- a/src/libcharon/plugins/eap_radius/Makefile.am
+++ b/src/libcharon/plugins/eap_radius/Makefile.am
@@ -13,6 +13,8 @@ endif
libstrongswan_eap_radius_la_SOURCES = \
eap_radius_plugin.h eap_radius_plugin.c \
eap_radius.h eap_radius.c \
+ radius_server.h radius_server.c \
+ radius_socket.h radius_socket.c \
radius_client.h radius_client.c \
radius_message.h radius_message.c
diff --git a/src/libcharon/plugins/eap_radius/Makefile.in b/src/libcharon/plugins/eap_radius/Makefile.in
index 18427adef..bb372d13c 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -75,7 +75,8 @@ am__installdirs = "$(DESTDIR)$(plugindir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
libstrongswan_eap_radius_la_LIBADD =
am_libstrongswan_eap_radius_la_OBJECTS = eap_radius_plugin.lo \
- eap_radius.lo radius_client.lo radius_message.lo
+ eap_radius.lo radius_server.lo radius_socket.lo \
+ radius_client.lo radius_message.lo
libstrongswan_eap_radius_la_OBJECTS = \
$(am_libstrongswan_eap_radius_la_OBJECTS)
libstrongswan_eap_radius_la_LINK = $(LIBTOOL) --tag=CC \
@@ -267,6 +268,8 @@ AM_CFLAGS = -rdynamic
libstrongswan_eap_radius_la_SOURCES = \
eap_radius_plugin.h eap_radius_plugin.c \
eap_radius.h eap_radius.c \
+ radius_server.h radius_server.c \
+ radius_socket.h radius_socket.c \
radius_client.h radius_client.c \
radius_message.h radius_message.c
@@ -358,6 +361,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_radius_plugin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_client.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_message.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_server.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_socket.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c
index f041fda54..65b868bc6 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius.c
@@ -53,11 +53,6 @@ struct private_eap_radius_t {
u_int32_t vendor;
/**
- * EAP MSK, if method established one
- */
- chunk_t msk;
-
- /**
* RADIUS client instance
*/
radius_client_t *client;
@@ -71,6 +66,11 @@ struct private_eap_radius_t {
* Prefix to prepend to EAP identity
*/
char *id_prefix;
+
+ /**
+ * Handle the Class attribute as group membership information?
+ */
+ bool class_group;
};
/**
@@ -140,10 +140,8 @@ static bool radius2ike(private_eap_radius_t *this,
return FALSE;
}
-/**
- * Implementation of eap_method_t.initiate
- */
-static status_t initiate(private_eap_radius_t *this, eap_payload_t **out)
+METHOD(eap_method_t, initiate, status_t,
+ private_eap_radius_t *this, eap_payload_t **out)
{
radius_message_t *request, *response;
status_t status = FAILED;
@@ -177,10 +175,44 @@ static status_t initiate(private_eap_radius_t *this, eap_payload_t **out)
}
/**
- * Implementation of eap_method_t.process
+ * Handle the Class attribute as group membership information
*/
-static status_t process(private_eap_radius_t *this,
- eap_payload_t *in, eap_payload_t **out)
+static void process_class(private_eap_radius_t *this, radius_message_t *msg)
+{
+ enumerator_t *enumerator;
+ chunk_t data;
+ int type;
+
+ enumerator = msg->create_enumerator(msg);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_CLASS)
+ {
+ identification_t *id;
+ ike_sa_t *ike_sa;
+ auth_cfg_t *auth;
+
+ if (data.len >= 44)
+ { /* quirk: ignore long class attributes, these are used for
+ * other purposes by some RADIUS servers (such as NPS). */
+ continue;
+ }
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa)
+ {
+ auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
+ id = identification_create_from_data(data);
+ DBG1(DBG_CFG, "received group membership '%Y' from RADIUS", id);
+ auth->add(auth, AUTH_RULE_GROUP, id);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(eap_method_t, process, status_t,
+ private_eap_radius_t *this, eap_payload_t *in, eap_payload_t **out)
{
radius_message_t *request, *response;
status_t status = FAILED;
@@ -211,8 +243,10 @@ static status_t process(private_eap_radius_t *this,
status = FAILED;
break;
case RMC_ACCESS_ACCEPT:
- this->msk = this->client->decrypt_msk(this->client,
- response, request);
+ if (this->class_group)
+ {
+ process_class(this, response);
+ }
status = SUCCESS;
break;
case RMC_ACCESS_REJECT:
@@ -228,32 +262,29 @@ static status_t process(private_eap_radius_t *this,
return status;
}
-/**
- * Implementation of eap_method_t.get_type.
- */
-static eap_type_t get_type(private_eap_radius_t *this, u_int32_t *vendor)
+METHOD(eap_method_t, get_type, eap_type_t,
+ private_eap_radius_t *this, u_int32_t *vendor)
{
*vendor = this->vendor;
return this->type;
}
-/**
- * Implementation of eap_method_t.get_msk.
- */
-static status_t get_msk(private_eap_radius_t *this, chunk_t *msk)
+METHOD(eap_method_t, get_msk, status_t,
+ private_eap_radius_t *this, chunk_t *out)
{
- if (this->msk.ptr)
+ chunk_t msk;
+
+ msk = this->client->get_msk(this->client);
+ if (msk.len)
{
- *msk = this->msk;
+ *out = msk;
return SUCCESS;
}
return FAILED;
}
-/**
- * Implementation of eap_method_t.is_mutual.
- */
-static bool is_mutual(private_eap_radius_t *this)
+METHOD(eap_method_t, is_mutual, bool,
+ private_eap_radius_t *this)
{
switch (this->type)
{
@@ -265,15 +296,12 @@ static bool is_mutual(private_eap_radius_t *this)
}
}
-/**
- * Implementation of eap_method_t.destroy.
- */
-static void destroy(private_eap_radius_t *this)
+METHOD(eap_method_t, destroy, void,
+ private_eap_radius_t *this)
{
this->peer->destroy(this->peer);
this->server->destroy(this->server);
this->client->destroy(this->client);
- chunk_clear(&this->msk);
free(this);
}
@@ -282,15 +310,26 @@ static void destroy(private_eap_radius_t *this)
*/
eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer)
{
- private_eap_radius_t *this = malloc_thing(private_eap_radius_t);
-
- this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
- this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
- this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
- this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
- this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
- this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
-
+ private_eap_radius_t *this;
+
+ INIT(this,
+ .public.eap_method_interface = {
+ .initiate = _initiate,
+ .process = _process,
+ .get_type = _get_type,
+ .is_mutual = _is_mutual,
+ .get_msk = _get_msk,
+ .destroy = _destroy,
+ },
+ /* initially EAP_RADIUS, but is set to the method selected by RADIUS */
+ .type = EAP_RADIUS,
+ .eap_start = lib->settings->get_bool(lib->settings,
+ "charon.plugins.eap-radius.eap_start", FALSE),
+ .id_prefix = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.id_prefix", ""),
+ .class_group = lib->settings->get_bool(lib->settings,
+ "charon.plugins.eap-radius.class_group", FALSE),
+ );
this->client = radius_client_create();
if (!this->client)
{
@@ -299,14 +338,6 @@ eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer
}
this->peer = peer->clone(peer);
this->server = server->clone(server);
- /* initially EAP_RADIUS, but is set to the method selected by RADIUS */
- this->type = EAP_RADIUS;
- this->vendor = 0;
- this->msk = chunk_empty;
- this->eap_start = lib->settings->get_bool(lib->settings,
- "charon.plugins.eap-radius.eap_start", FALSE);
- this->id_prefix = lib->settings->get_str(lib->settings,
- "charon.plugins.eap-radius.id_prefix", "");
return &this->public;
}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
index 7d2788c3e..91aae2f62 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
@@ -17,17 +17,130 @@
#include "eap_radius.h"
#include "radius_client.h"
+#include "radius_server.h"
#include <daemon.h>
/**
- * Implementation of plugin_t.destroy
+ * Default RADIUS server port, when not configured
*/
-static void destroy(eap_radius_plugin_t *this)
+#define RADIUS_PORT 1812
+
+typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t;
+
+/**
+ * Private data of an eap_radius_plugin_t object.
+ */
+struct private_eap_radius_plugin_t {
+
+ /**
+ * Public radius_plugin_t interface.
+ */
+ eap_radius_plugin_t public;
+
+ /**
+ * List of RADIUS servers
+ */
+ linked_list_t *servers;
+};
+
+/**
+ * Instance of the EAP plugin
+ */
+static private_eap_radius_plugin_t *instance = NULL;
+
+METHOD(plugin_t, destroy, void,
+ private_eap_radius_plugin_t *this)
{
charon->eap->remove_method(charon->eap, (eap_constructor_t)eap_radius_create);
- radius_client_cleanup();
+ this->servers->destroy_offset(this->servers,
+ offsetof(radius_server_t, destroy));
free(this);
+ instance = NULL;
+}
+
+/**
+ * Load RADIUS servers from configuration
+ */
+static bool load_servers(private_eap_radius_plugin_t *this)
+{
+ enumerator_t *enumerator;
+ radius_server_t *server;
+ char *nas_identifier, *secret, *address, *section;
+ int port, sockets, preference;
+
+ address = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.server", NULL);
+ if (address)
+ { /* legacy configuration */
+ secret = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.secret", NULL);
+ if (!secret)
+ {
+ DBG1(DBG_CFG, "no RADUIS secret defined");
+ return FALSE;
+ }
+ nas_identifier = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.nas_identifier", "strongSwan");
+ port = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.port", RADIUS_PORT);
+ sockets = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.sockets", 1);
+ server = radius_server_create(address, port, nas_identifier,
+ secret, sockets, 0);
+ if (!server)
+ {
+ DBG1(DBG_CFG, "no RADUIS server defined");
+ return FALSE;
+ }
+ this->servers->insert_last(this->servers, server);
+ return TRUE;
+ }
+
+ enumerator = lib->settings->create_section_enumerator(lib->settings,
+ "charon.plugins.eap-radius.servers");
+ while (enumerator->enumerate(enumerator, &section))
+ {
+ address = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.address", NULL, section);
+ if (!address)
+ {
+ DBG1(DBG_CFG, "RADIUS server '%s' misses address, skipped", section);
+ continue;
+ }
+ secret = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.secret", NULL, section);
+ if (!secret)
+ {
+ DBG1(DBG_CFG, "RADIUS server '%s' misses secret, skipped", section);
+ continue;
+ }
+ nas_identifier = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.nas_identifier",
+ "strongSwan", section);
+ port = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.port", RADIUS_PORT, section);
+ sockets = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.sockets", 1, section);
+ preference = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.preference", 0, section);
+ server = radius_server_create(address, port, nas_identifier,
+ secret, sockets, preference);
+ if (!server)
+ {
+ DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section);
+ continue;
+ }
+ this->servers->insert_last(this->servers, server);
+ }
+ enumerator->destroy(enumerator);
+
+ if (this->servers->get_count(this->servers) == 0)
+ {
+ DBG1(DBG_CFG, "no valid RADIUS server configuration found");
+ return FALSE;
+ }
+ return TRUE;
}
/*
@@ -35,20 +148,35 @@ static void destroy(eap_radius_plugin_t *this)
*/
plugin_t *eap_radius_plugin_create()
{
- eap_radius_plugin_t *this;
+ private_eap_radius_plugin_t *this;
+
+ INIT(this,
+ .public.plugin.destroy = _destroy,
+ .servers = linked_list_create(),
+ );
- if (!radius_client_init())
+ if (!load_servers(this))
{
- DBG1(DBG_CFG, "RADIUS plugin initialization failed");
+ destroy(this);
return NULL;
}
-
- this = malloc_thing(eap_radius_plugin_t);
- this->plugin.destroy = (void(*)(plugin_t*))destroy;
-
charon->eap->add_method(charon->eap, EAP_RADIUS, 0,
EAP_SERVER, (eap_constructor_t)eap_radius_create);
- return &this->plugin;
+ instance = this;
+
+ return &this->public.plugin;
+}
+
+/**
+ * See header
+ */
+enumerator_t *eap_radius_create_server_enumerator()
+{
+ if (instance)
+ {
+ return instance->servers->create_enumerator(instance->servers);
+ }
+ return enumerator_create_empty();
}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.h b/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
index f2b8b5082..cb724364a 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
+++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
@@ -25,6 +25,7 @@
#define EAP_RADIUS_PLUGIN_H_
#include <plugins/plugin.h>
+#include <utils/enumerator.h>
typedef struct eap_radius_plugin_t eap_radius_plugin_t;
@@ -42,4 +43,11 @@ struct eap_radius_plugin_t {
plugin_t plugin;
};
+/**
+ * Create an enumerator over all loaded RADIUS servers.
+ *
+ * @return enumerator over radius_server_t
+ */
+enumerator_t *eap_radius_create_server_enumerator();
+
#endif /** EAP_RADIUS_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_client.c b/src/libcharon/plugins/eap_radius/radius_client.c
index 1d1f21742..232b9135e 100644
--- a/src/libcharon/plugins/eap_radius/radius_client.c
+++ b/src/libcharon/plugins/eap_radius/radius_client.c
@@ -15,6 +15,9 @@
#include "radius_client.h"
+#include "eap_radius_plugin.h"
+#include "radius_server.h"
+
#include <unistd.h>
#include <errno.h>
@@ -24,42 +27,8 @@
#include <threading/condvar.h>
#include <threading/mutex.h>
-/**
- * Default RADIUS server port, when not configured
- */
-#define RADIUS_PORT 1812
-
-/**
- * Vendor-Id of Microsoft specific attributes
- */
-#define VENDOR_ID_MICROSOFT 311
-
-/**
- * Microsoft specific vendor attributes
- */
-#define MS_MPPE_SEND_KEY 16
-#define MS_MPPE_RECV_KEY 17
-
typedef struct private_radius_client_t private_radius_client_t;
-typedef struct entry_t entry_t;
-
-/**
- * A socket pool entry.
- */
-struct entry_t {
- /** socket file descriptor */
- int fd;
- /** current RADIUS identifier */
- u_int8_t identifier;
- /** hasher to use for response verification */
- hasher_t *hasher;
- /** HMAC-MD5 signer to build Message-Authenticator attribute */
- signer_t *signer;
- /** random number generator for RADIUS request authenticator */
- rng_t *rng;
-};
-
/**
* Private data of an radius_client_t object.
*/
@@ -71,170 +40,20 @@ struct private_radius_client_t {
radius_client_t public;
/**
+ * Selected RADIUS server
+ */
+ radius_server_t *server;
+
+ /**
* RADIUS servers State attribute
*/
chunk_t state;
-};
-/**
- * Global list of radius sockets, contains entry_t's
- */
-static linked_list_t *sockets;
-
-/**
- * mutex to lock sockets list
- */
-static mutex_t *mutex;
-
-/**
- * condvar to wait for sockets
- */
-static condvar_t *condvar;
-
-/**
- * RADIUS secret
- */
-static chunk_t secret;
-
-/**
- * NAS-Identifier
- */
-static chunk_t nas_identifier;
-
-/**
- * Clean up socket list
- */
-void radius_client_cleanup()
-{
- entry_t *entry;
-
- mutex->destroy(mutex);
- condvar->destroy(condvar);
- while (sockets->remove_last(sockets, (void**)&entry) == SUCCESS)
- {
- entry->rng->destroy(entry->rng);
- entry->hasher->destroy(entry->hasher);
- entry->signer->destroy(entry->signer);
- close(entry->fd);
- free(entry);
- }
- sockets->destroy(sockets);
-}
-
-/**
- * Initialize the socket list
- */
-bool radius_client_init()
-{
- int i, count, fd;
- u_int16_t port;
- entry_t *entry;
- host_t *host;
- char *server;
-
- nas_identifier.ptr = lib->settings->get_str(lib->settings,
- "charon.plugins.eap-radius.nas_identifier", "strongSwan");
- nas_identifier.len = strlen(nas_identifier.ptr);
-
- secret.ptr = lib->settings->get_str(lib->settings,
- "charon.plugins.eap-radius.secret", NULL);
- if (!secret.ptr)
- {
- DBG1(DBG_CFG, "no RADUIS secret defined");
- return FALSE;
- }
- secret.len = strlen(secret.ptr);
- server = lib->settings->get_str(lib->settings,
- "charon.plugins.eap-radius.server", NULL);
- if (!server)
- {
- DBG1(DBG_CFG, "no RADUIS server defined");
- return FALSE;
- }
- port = lib->settings->get_int(lib->settings,
- "charon.plugins.eap-radius.port", RADIUS_PORT);
- host = host_create_from_dns(server, 0, port);
- if (!host)
- {
- return FALSE;
- }
- count = lib->settings->get_int(lib->settings,
- "charon.plugins.eap-radius.sockets", 1);
-
- sockets = linked_list_create();
- mutex = mutex_create(MUTEX_TYPE_DEFAULT);
- condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
- for (i = 0; i < count; i++)
- {
- fd = socket(host->get_family(host), SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0)
- {
- DBG1(DBG_CFG, "opening RADIUS socket failed");
- host->destroy(host);
- radius_client_cleanup();
- return FALSE;
- }
- if (connect(fd, host->get_sockaddr(host),
- *host->get_sockaddr_len(host)) < 0)
- {
- DBG1(DBG_CFG, "connecting RADIUS socket failed");
- host->destroy(host);
- radius_client_cleanup();
- return FALSE;
- }
- entry = malloc_thing(entry_t);
- entry->fd = fd;
- /* we use per-socket crypto elements: this reduces overhead, but
- * is still thread-save. */
- entry->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
- entry->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128);
- entry->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
- if (!entry->hasher || !entry->signer || !entry->rng)
- {
- DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required");
- DESTROY_IF(entry->hasher);
- DESTROY_IF(entry->signer);
- DESTROY_IF(entry->rng);
- free(entry);
- host->destroy(host);
- radius_client_cleanup();
- return FALSE;
- }
- entry->signer->set_key(entry->signer, secret);
- /* we use a random identifier, helps if we restart often (testing) */
- entry->identifier = random();
- sockets->insert_last(sockets, entry);
- }
- host->destroy(host);
- return TRUE;
-}
-
-/**
- * Get a socket from the pool, block if none available
- */
-static entry_t* get_socket()
-{
- entry_t *entry;
-
- mutex->lock(mutex);
- while (sockets->remove_first(sockets, (void**)&entry) != SUCCESS)
- {
- condvar->wait(condvar, mutex);
- }
- mutex->unlock(mutex);
- return entry;
-}
-
-/**
- * Release a socket to the pool
- */
-static void put_socket(entry_t *entry)
-{
- mutex->lock(mutex);
- sockets->insert_last(sockets, entry);
- mutex->unlock(mutex);
- condvar->signal(condvar);
-}
+ /**
+ * EAP MSK, from MPPE keys
+ */
+ chunk_t msk;
+};
/**
* Save the state attribute to include in further request
@@ -261,234 +80,103 @@ static void save_state(private_radius_client_t *this, radius_message_t *msg)
chunk_free(&this->state);
}
-/**
- * Implementation of radius_client_t.request
- */
-static radius_message_t* request(private_radius_client_t *this,
- radius_message_t *req)
+METHOD(radius_client_t, request, radius_message_t*,
+ private_radius_client_t *this, radius_message_t *req)
{
char virtual[] = {0x00,0x00,0x00,0x05};
- entry_t *socket;
- chunk_t data;
- int i;
+ radius_socket_t *socket;
+ radius_message_t *res;
- socket = get_socket();
-
- /* set Message Identifier */
- req->set_identifier(req, socket->identifier++);
/* we add the "Virtual" NAS-Port-Type, as we SHOULD include one */
req->add(req, RAT_NAS_PORT_TYPE, chunk_create(virtual, sizeof(virtual)));
/* add our NAS-Identifier */
- req->add(req, RAT_NAS_IDENTIFIER, nas_identifier);
+ req->add(req, RAT_NAS_IDENTIFIER,
+ this->server->get_nas_identifier(this->server));
/* add State attribute, if server sent one */
if (this->state.ptr)
{
req->add(req, RAT_STATE, this->state);
}
- /* sign the request */
- req->sign(req, socket->rng, socket->signer);
-
- data = req->get_encoding(req);
- /* timeout after 2, 3, 4, 5 seconds */
- for (i = 2; i <= 5; i++)
+ socket = this->server->get_socket(this->server);
+ DBG1(DBG_CFG, "sending RADIUS %N to %#H", radius_message_code_names,
+ req->get_code(req), this->server->get_address(this->server));
+ res = socket->request(socket, req);
+ if (res)
{
- radius_message_t *response;
- bool retransmit = FALSE;
- struct timeval tv;
- char buf[4096];
- fd_set fds;
- int res;
-
- if (send(socket->fd, data.ptr, data.len, 0) != data.len)
- {
- DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
- put_socket(socket);
- return NULL;
- }
- tv.tv_sec = i;
- tv.tv_usec = 0;
-
- while (TRUE)
+ DBG1(DBG_CFG, "received RADIUS %N from %#H", radius_message_code_names,
+ res->get_code(res), this->server->get_address(this->server));
+ save_state(this, res);
+ if (res->get_code(res) == RMC_ACCESS_ACCEPT)
{
- FD_ZERO(&fds);
- FD_SET(socket->fd, &fds);
- res = select(socket->fd + 1, &fds, NULL, NULL, &tv);
- /* TODO: updated tv to time not waited. Linux does this for us. */
- if (res < 0)
- { /* failed */
- DBG1(DBG_CFG, "waiting for RADIUS message failed: %s",
- strerror(errno));
- break;
- }
- if (res == 0)
- { /* timeout */
- DBG1(DBG_CFG, "retransmitting RADIUS message");
- retransmit = TRUE;
- break;
- }
- res = recv(socket->fd, buf, sizeof(buf), MSG_DONTWAIT);
- if (res <= 0)
- {
- DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
- strerror(errno));
- break;
- }
- response = radius_message_parse_response(chunk_create(buf, res));
- if (response)
- {
- if (response->verify(response, req->get_authenticator(req),
- secret, socket->hasher, socket->signer))
- {
- save_state(this, response);
- put_socket(socket);
- return response;
- }
- response->destroy(response);
- }
- DBG1(DBG_CFG, "received invalid RADIUS message, ignored");
- }
- if (!retransmit)
- {
- break;
+ chunk_clear(&this->msk);
+ this->msk = socket->decrypt_msk(socket, req, res);
}
+ this->server->put_socket(this->server, socket, TRUE);
+ return res;
}
- DBG1(DBG_CFG, "RADIUS server is not responding");
- put_socket(socket);
+ this->server->put_socket(this->server, socket, FALSE);
charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING);
return NULL;
}
-/**
- * Decrypt a MS-MPPE-Send/Recv-Key
- */
-static chunk_t decrypt_mppe_key(private_radius_client_t *this, u_int16_t salt,
- chunk_t C, radius_message_t *request)
+METHOD(radius_client_t, get_msk, chunk_t,
+ private_radius_client_t *this)
{
- chunk_t A, R, P, seed;
- u_char *c, *p;
- hasher_t *hasher;
-
- /**
- * From RFC2548 (encryption):
- * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
- * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
- * . . .
- * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
- */
-
- if (C.len % HASH_SIZE_MD5 || C.len < HASH_SIZE_MD5)
- {
- return chunk_empty;
- }
-
- hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
- if (!hasher)
- {
- return chunk_empty;
- }
-
- A = chunk_create((u_char*)&salt, sizeof(salt));
- R = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5);
- P = chunk_alloca(C.len);
- p = P.ptr;
- c = C.ptr;
-
- seed = chunk_cata("cc", R, A);
-
- while (c < C.ptr + C.len)
- {
- /* b(i) = MD5(S + c(i-1)) */
- hasher->get_hash(hasher, secret, NULL);
- hasher->get_hash(hasher, seed, p);
-
- /* p(i) = b(i) xor c(1) */
- memxor(p, c, HASH_SIZE_MD5);
-
- /* prepare next round */
- seed = chunk_create(c, HASH_SIZE_MD5);
- c += HASH_SIZE_MD5;
- p += HASH_SIZE_MD5;
- }
- hasher->destroy(hasher);
+ return this->msk;
+}
- /* remove truncation, first byte is key length */
- if (*P.ptr >= P.len)
- { /* decryption failed? */
- return chunk_empty;
- }
- return chunk_clone(chunk_create(P.ptr + 1, *P.ptr));
+METHOD(radius_client_t, destroy, void,
+ private_radius_client_t *this)
+{
+ chunk_clear(&this->msk);
+ free(this->state.ptr);
+ free(this);
}
/**
- * Implementation of radius_client_t.decrypt_msk
+ * See header
*/
-static chunk_t decrypt_msk(private_radius_client_t *this,
- radius_message_t *response, radius_message_t *request)
+radius_client_t *radius_client_create()
{
- struct {
- u_int32_t id;
- u_int8_t type;
- u_int8_t length;
- u_int16_t salt;
- u_int8_t key[];
- } __attribute__((packed)) *mppe_key;
+ private_radius_client_t *this;
enumerator_t *enumerator;
- chunk_t data, send = chunk_empty, recv = chunk_empty;
- int type;
-
- enumerator = response->create_enumerator(response);
- while (enumerator->enumerate(enumerator, &type, &data))
+ radius_server_t *server;
+ int current, best = -1;
+
+ INIT(this,
+ .public = {
+ .request = _request,
+ .get_msk = _get_msk,
+ .destroy = _destroy,
+ },
+ );
+
+ enumerator = eap_radius_create_server_enumerator();
+ while (enumerator->enumerate(enumerator, &server))
{
- if (type == RAT_VENDOR_SPECIFIC &&
- data.len > sizeof(*mppe_key))
+ current = server->get_preference(server);
+ if (current > best ||
+ /* for two with equal preference, 50-50 chance */
+ (current == best && random() % 2 == 0))
+ {
+ DBG2(DBG_CFG, "RADIUS server %H is candidate: %d",
+ server->get_address(server), current);
+ best = current;
+ this->server = server;
+ }
+ else
{
- mppe_key = (void*)data.ptr;
- if (ntohl(mppe_key->id) == VENDOR_ID_MICROSOFT &&
- mppe_key->length == data.len - sizeof(mppe_key->id))
- {
- data = chunk_create(mppe_key->key, data.len - sizeof(*mppe_key));
- if (mppe_key->type == MS_MPPE_SEND_KEY)
- {
- send = decrypt_mppe_key(this, mppe_key->salt, data, request);
- }
- if (mppe_key->type == MS_MPPE_RECV_KEY)
- {
- recv = decrypt_mppe_key(this, mppe_key->salt, data, request);
- }
- }
+ DBG2(DBG_CFG, "RADIUS server %H skipped: %d",
+ server->get_address(server), current);
}
}
enumerator->destroy(enumerator);
- if (send.ptr && recv.ptr)
+
+ if (!this->server)
{
- return chunk_cat("mm", recv, send);
+ free(this);
+ return NULL;
}
- chunk_clear(&send);
- chunk_clear(&recv);
- return chunk_empty;
-}
-
-/**
- * Implementation of radius_client_t.destroy.
- */
-static void destroy(private_radius_client_t *this)
-{
- free(this->state.ptr);
- free(this);
-}
-
-/**
- * See header
- */
-radius_client_t *radius_client_create()
-{
- private_radius_client_t *this = malloc_thing(private_radius_client_t);
-
- this->public.request = (radius_message_t*(*)(radius_client_t*, radius_message_t *msg))request;
- this->public.decrypt_msk = (chunk_t(*)(radius_client_t*, radius_message_t *, radius_message_t *))decrypt_msk;
- this->public.destroy = (void(*)(radius_client_t*))destroy;
-
- this->state = chunk_empty;
return &this->public;
}
diff --git a/src/libcharon/plugins/eap_radius/radius_client.h b/src/libcharon/plugins/eap_radius/radius_client.h
index 77ba94807..e4f3a7222 100644
--- a/src/libcharon/plugins/eap_radius/radius_client.h
+++ b/src/libcharon/plugins/eap_radius/radius_client.h
@@ -29,19 +29,14 @@ typedef struct radius_client_t radius_client_t;
* RADIUS client functionality.
*
* To communicate with a RADIUS server, create a client and send messages over
- * it. All instances share a fixed size pool of sockets. The client reserves
- * a socket during request() and releases it afterwards.
+ * it. The client allocates a socket from the best RADIUS server abailable.
*/
struct radius_client_t {
/**
* Send a RADIUS request and wait for the response.
*
- * The client fills in RADIUS Message identifier, NAS-Identifier,
- * NAS-Port-Type, builds a Request-Authenticator and calculates the
- * Message-Authenticator attribute.
- * The received response gets verified using the Response-Identifier
- * and the Message-Authenticator attribute.
+ * The client fills in NAS-Identifier nad NAS-Port-Type
*
* @param msg RADIUS request message to send
* @return response, NULL if timed out/verification failed
@@ -49,14 +44,11 @@ struct radius_client_t {
radius_message_t* (*request)(radius_client_t *this, radius_message_t *msg);
/**
- * Decrypt the MSK encoded in a messages MS-MPPE-Send/Recv-Key.
+ * Get the EAP MSK after successful RADIUS authentication.
*
- * @param response RADIUS response message containing attributes
- * @param request associated RADIUS request message
- * @return allocated MSK, empty chunk if none found
+ * @return MSK, allocated
*/
- chunk_t (*decrypt_msk)(radius_client_t *this, radius_message_t *response,
- radius_message_t *request);
+ chunk_t (*get_msk)(radius_client_t *this);
/**
* Destroy the client, release the socket.
@@ -65,24 +57,10 @@ struct radius_client_t {
};
/**
- * Create a RADIUS client, acquire a socket.
- *
- * This call might block if the socket pool is empty.
+ * Create a RADIUS client.
*
* @return radius_client_t object
*/
radius_client_t *radius_client_create();
-/**
- * Initialize the socket pool.
- *
- * @return TRUE if initialization successful
- */
-bool radius_client_init();
-
-/**
- * Cleanup the socket pool.
- */
-void radius_client_cleanup();
-
#endif /** RADIUS_CLIENT_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_message.c b/src/libcharon/plugins/eap_radius/radius_message.c
index 11a1d8dfc..23a29b772 100644
--- a/src/libcharon/plugins/eap_radius/radius_message.c
+++ b/src/libcharon/plugins/eap_radius/radius_message.c
@@ -215,13 +215,8 @@ typedef struct {
int left;
} attribute_enumerator_t;
-
-/**
- * Implementation of attribute_enumerator_t.enumerate
- */
-static bool attribute_enumerate(attribute_enumerator_t *this,
- int *type, chunk_t *data)
-
+METHOD(enumerator_t, attribute_enumerate, bool,
+ attribute_enumerator_t *this, int *type, chunk_t *data)
{
if (this->left == 0)
{
@@ -241,10 +236,8 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
return TRUE;
}
-/**
- * Implementation of radius_message_t.create_enumerator
- */
-static enumerator_t* create_enumerator(private_radius_message_t *this)
+METHOD(radius_message_t, create_enumerator, enumerator_t*,
+ private_radius_message_t *this)
{
attribute_enumerator_t *e;
@@ -252,20 +245,19 @@ static enumerator_t* create_enumerator(private_radius_message_t *this)
{
return enumerator_create_empty();
}
-
- e = malloc_thing(attribute_enumerator_t);
- e->public.enumerate = (void*)attribute_enumerate;
- e->public.destroy = (void*)free;
- e->next = (rattr_t*)this->msg->attributes;
- e->left = ntohs(this->msg->length) - sizeof(rmsg_t);
+ INIT(e,
+ .public = {
+ .enumerate = (void*)_attribute_enumerate,
+ .destroy = (void*)free,
+ },
+ .next = (rattr_t*)this->msg->attributes,
+ .left = ntohs(this->msg->length) - sizeof(rmsg_t),
+ );
return &e->public;
}
-/**
- * Implementation of radius_message_t.add
- */
-static void add(private_radius_message_t *this, radius_attribute_type_t type,
- chunk_t data)
+METHOD(radius_message_t, add, void,
+ private_radius_message_t *this, radius_attribute_type_t type, chunk_t data)
{
rattr_t *attribute;
@@ -279,10 +271,8 @@ static void add(private_radius_message_t *this, radius_attribute_type_t type,
this->msg->length = htons(ntohs(this->msg->length) + attribute->length);
}
-/**
- * Implementation of radius_message_t.sign
- */
-static void sign(private_radius_message_t *this, rng_t *rng, signer_t *signer)
+METHOD(radius_message_t, sign, void,
+ private_radius_message_t *this, rng_t *rng, signer_t *signer)
{
char buf[HASH_SIZE_MD5];
@@ -297,11 +287,9 @@ static void sign(private_radius_message_t *this, rng_t *rng, signer_t *signer)
((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5);
}
-/**
- * Implementation of radius_message_t.verify
- */
-static bool verify(private_radius_message_t *this, u_int8_t *req_auth,
- chunk_t secret, hasher_t *hasher, signer_t *signer)
+METHOD(radius_message_t, verify, bool,
+ private_radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
+ hasher_t *hasher, signer_t *signer)
{
char buf[HASH_SIZE_MD5], res_auth[HASH_SIZE_MD5];
enumerator_t *enumerator;
@@ -369,51 +357,39 @@ static bool verify(private_radius_message_t *this, u_int8_t *req_auth,
return TRUE;
}
-/**
- * Implementation of radius_message_t.get_code
- */
-static radius_message_code_t get_code(private_radius_message_t *this)
+METHOD(radius_message_t, get_code, radius_message_code_t,
+ private_radius_message_t *this)
{
return this->msg->code;
}
-/**
- * Implementation of radius_message_t.get_identifier
- */
-static u_int8_t get_identifier(private_radius_message_t *this)
+METHOD(radius_message_t, get_identifier, u_int8_t,
+ private_radius_message_t *this)
{
return this->msg->identifier;
}
-/**
- * Implementation of radius_message_t.set_identifier
- */
-static void set_identifier(private_radius_message_t *this, u_int8_t identifier)
+METHOD(radius_message_t, set_identifier, void,
+ private_radius_message_t *this, u_int8_t identifier)
{
this->msg->identifier = identifier;
}
-/**
- * Implementation of radius_message_t.get_authenticator
- */
-static u_int8_t* get_authenticator(private_radius_message_t *this)
+METHOD(radius_message_t, get_authenticator, u_int8_t*,
+ private_radius_message_t *this)
{
return this->msg->authenticator;
}
-/**
- * Implementation of radius_message_t.get_encoding
- */
-static chunk_t get_encoding(private_radius_message_t *this)
+METHOD(radius_message_t, get_encoding, chunk_t,
+ private_radius_message_t *this)
{
return chunk_create((u_char*)this->msg, ntohs(this->msg->length));
}
-/**
- * Implementation of radius_message_t.destroy.
- */
-static void destroy(private_radius_message_t *this)
+METHOD(radius_message_t, destroy, void,
+ private_radius_message_t *this)
{
free(this->msg);
free(this);
@@ -424,18 +400,22 @@ static void destroy(private_radius_message_t *this)
*/
static private_radius_message_t *radius_message_create()
{
- private_radius_message_t *this = malloc_thing(private_radius_message_t);
-
- this->public.create_enumerator = (enumerator_t*(*)(radius_message_t*))create_enumerator;
- this->public.add = (void(*)(radius_message_t*, radius_attribute_type_t,chunk_t))add;
- this->public.get_code = (radius_message_code_t(*)(radius_message_t*))get_code;
- this->public.get_identifier = (u_int8_t(*)(radius_message_t*))get_identifier;
- this->public.set_identifier = (void(*)(radius_message_t*, u_int8_t identifier))set_identifier;
- this->public.get_authenticator = (u_int8_t*(*)(radius_message_t*))get_authenticator;
- this->public.get_encoding = (chunk_t(*)(radius_message_t*))get_encoding;
- this->public.sign = (void(*)(radius_message_t*, rng_t *rng, signer_t *signer))sign;
- this->public.verify = (bool(*)(radius_message_t*, u_int8_t *req_auth, chunk_t secret, hasher_t *hasher, signer_t *signer))verify;
- this->public.destroy = (void(*)(radius_message_t*))destroy;
+ private_radius_message_t *this;
+
+ INIT(this,
+ .public = {
+ .create_enumerator = _create_enumerator,
+ .add = _add,
+ .get_code = _get_code,
+ .get_identifier = _get_identifier,
+ .set_identifier = _set_identifier,
+ .get_authenticator = _get_authenticator,
+ .get_encoding = _get_encoding,
+ .sign = _sign,
+ .verify = _verify,
+ .destroy = _destroy,
+ },
+ );
return this;
}
@@ -447,10 +427,11 @@ radius_message_t *radius_message_create_request()
{
private_radius_message_t *this = radius_message_create();
- this->msg = malloc_thing(rmsg_t);
- this->msg->code = RMC_ACCESS_REQUEST;
- this->msg->identifier = 0;
- this->msg->length = htons(sizeof(rmsg_t));
+ INIT(this->msg,
+ .code = RMC_ACCESS_REQUEST,
+ .identifier = 0,
+ .length = htons(sizeof(rmsg_t)),
+ );
return &this->public;
}
diff --git a/src/libcharon/plugins/eap_radius/radius_server.c b/src/libcharon/plugins/eap_radius/radius_server.c
new file mode 100644
index 000000000..f54b8b2cd
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/radius_server.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "radius_server.h"
+
+#include <threading/mutex.h>
+#include <threading/condvar.h>
+#include <utils/linked_list.h>
+
+typedef struct private_radius_server_t private_radius_server_t;
+
+/**
+ * Private data of an radius_server_t object.
+ */
+struct private_radius_server_t {
+
+ /**
+ * Public radius_server_t interface.
+ */
+ radius_server_t public;
+
+ /**
+ * RADIUS server address
+ */
+ host_t *host;
+
+ /**
+ * list of radius sockets, as radius_socket_t
+ */
+ linked_list_t *sockets;
+
+ /**
+ * Total number of sockets, in list + currently in use
+ */
+ int socket_count;
+
+ /**
+ * mutex to lock sockets list
+ */
+ mutex_t *mutex;
+
+ /**
+ * condvar to wait for sockets
+ */
+ condvar_t *condvar;
+
+ /**
+ * RADIUS secret
+ */
+ chunk_t secret;
+
+ /**
+ * NAS-Identifier
+ */
+ chunk_t nas_identifier;
+
+ /**
+ * Preference boost for this server
+ */
+ int preference;
+
+ /**
+ * Is the server currently reachable
+ */
+ bool reachable;
+
+ /**
+ * Retry counter for unreachable servers
+ */
+ int retry;
+};
+
+METHOD(radius_server_t, get_socket, radius_socket_t*,
+ private_radius_server_t *this)
+{
+ radius_socket_t *skt;
+
+ this->mutex->lock(this->mutex);
+ while (this->sockets->remove_first(this->sockets, (void**)&skt) != SUCCESS)
+ {
+ this->condvar->wait(this->condvar, this->mutex);
+ }
+ this->mutex->unlock(this->mutex);
+ return skt;
+}
+
+METHOD(radius_server_t, put_socket, void,
+ private_radius_server_t *this, radius_socket_t *skt, bool result)
+{
+ this->mutex->lock(this->mutex);
+ this->sockets->insert_last(this->sockets, skt);
+ this->mutex->unlock(this->mutex);
+ this->condvar->signal(this->condvar);
+ this->reachable = result;
+}
+
+METHOD(radius_server_t, get_nas_identifier, chunk_t,
+ private_radius_server_t *this)
+{
+ return this->nas_identifier;
+}
+
+METHOD(radius_server_t, get_preference, int,
+ private_radius_server_t *this)
+{
+ int pref;
+
+ if (this->socket_count == 0)
+ { /* don't have sockets, huh? */
+ return -1;
+ }
+ /* calculate preference between 0-100 + boost */
+ pref = this->preference;
+ pref += this->sockets->get_count(this->sockets) * 100 / this->socket_count;
+ if (this->reachable)
+ { /* reachable server get a boost: pref = 110-210 + boost */
+ return pref + 110;
+ }
+ /* Not reachable. Increase preference randomly to let it retry from
+ * time to time, especially if other servers have high load. */
+ this->retry++;
+ if (this->retry % 128 == 0)
+ { /* every 64th request gets 210, same as unloaded reachable */
+ return pref + 110;
+ }
+ if (this->retry % 32 == 0)
+ { /* every 32th request gets 190, wins against average loaded */
+ return pref + 90;
+ }
+ if (this->retry % 8 == 0)
+ { /* every 8th request gets 110, same as server under load */
+ return pref + 10;
+ }
+ /* other get ~100, less than fully loaded */
+ return pref;
+}
+
+METHOD(radius_server_t, get_address, host_t*,
+ private_radius_server_t *this)
+{
+ return this->host;
+}
+
+METHOD(radius_server_t, destroy, void,
+ private_radius_server_t *this)
+{
+ DESTROY_IF(this->host);
+ this->mutex->destroy(this->mutex);
+ this->condvar->destroy(this->condvar);
+ this->sockets->destroy_offset(this->sockets,
+ offsetof(radius_socket_t, destroy));
+ free(this);
+}
+
+/**
+ * See header
+ */
+radius_server_t *radius_server_create(char *server, u_int16_t port,
+ char *nas_identifier, char *secret, int sockets, int preference)
+{
+ private_radius_server_t *this;
+ radius_socket_t *socket;
+
+ INIT(this,
+ .public = {
+ .get_socket = _get_socket,
+ .put_socket = _put_socket,
+ .get_nas_identifier = _get_nas_identifier,
+ .get_preference = _get_preference,
+ .get_address = _get_address,
+ .destroy = _destroy,
+ },
+ .reachable = TRUE,
+ .nas_identifier = chunk_create(nas_identifier, strlen(nas_identifier)),
+ .socket_count = sockets,
+ .sockets = linked_list_create(),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .host = host_create_from_dns(server, 0, port),
+ .preference = preference,
+ );
+
+ if (!this->host)
+ {
+ destroy(this);
+ return NULL;
+ }
+ while (sockets--)
+ {
+ socket = radius_socket_create(this->host,
+ chunk_create(secret, strlen(secret)));
+ if (!socket)
+ {
+ destroy(this);
+ return NULL;
+ }
+ this->sockets->insert_last(this->sockets, socket);
+ }
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/radius_server.h b/src/libcharon/plugins/eap_radius/radius_server.h
new file mode 100644
index 000000000..b820cb583
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/radius_server.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 radius_server radius_server
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef RADIUS_SERVER_H_
+#define RADIUS_SERVER_H_
+
+typedef struct radius_server_t radius_server_t;
+
+#include "radius_socket.h"
+
+/**
+ * RADIUS server configuration.
+ */
+struct radius_server_t {
+
+ /**
+ * Get a RADIUS socket from the pool to communicate with this server.
+ *
+ * @return RADIUS socket
+ */
+ radius_socket_t* (*get_socket)(radius_server_t *this);
+
+ /**
+ * Release a socket to the pool after use.
+ *
+ * @param skt RADIUS socket to release
+ * @param result result of the socket use, TRUE for success
+ */
+ void (*put_socket)(radius_server_t *this, radius_socket_t *skt, bool result);
+
+ /**
+ * Get the NAS-Identifier to use with this server.
+ *
+ * @return NAS-Identifier, internal data
+ */
+ chunk_t (*get_nas_identifier)(radius_server_t *this);
+
+ /**
+ * Get the preference of this server.
+ *
+ * Based on the available sockets and the server reachability a preference
+ * value is calculated: better servers return a higher value.
+ */
+ int (*get_preference)(radius_server_t *this);
+
+ /**
+ * Get the address of the RADIUS server.
+ *
+ * @return address, internal data
+ */
+ host_t* (*get_address)(radius_server_t *this);
+
+ /**
+ * Destroy a radius_server_t.
+ */
+ void (*destroy)(radius_server_t *this);
+};
+
+/**
+ * Create a radius_server instance.
+ *
+ * @param server server address
+ * @param port server port
+ * @param nas_identifier NAS-Identifier to use with this server
+ * @param sockets number of sockets to create in pool
+ * @param preference preference boost for this server
+ */
+radius_server_t *radius_server_create(char *server, u_int16_t port,
+ char *nas_identifier, char *secret, int sockets, int preference);
+
+#endif /** RADIUS_SERVER_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_socket.c b/src/libcharon/plugins/eap_radius/radius_socket.c
new file mode 100644
index 000000000..f46c27ede
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/radius_socket.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "radius_socket.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <debug.h>
+
+/**
+ * Vendor-Id of Microsoft specific attributes
+ */
+#define VENDOR_ID_MICROSOFT 311
+
+/**
+ * Microsoft specific vendor attributes
+ */
+#define MS_MPPE_SEND_KEY 16
+#define MS_MPPE_RECV_KEY 17
+
+typedef struct private_radius_socket_t private_radius_socket_t;
+
+/**
+ * Private data of an radius_socket_t object.
+ */
+struct private_radius_socket_t {
+
+ /**
+ * Public radius_socket_t interface.
+ */
+ radius_socket_t public;
+
+ /**
+ * socket file descriptor
+ */
+ int fd;
+
+ /**
+ * current RADIUS identifier
+ */
+ u_int8_t identifier;
+
+ /**
+ * hasher to use for response verification
+ */
+ hasher_t *hasher;
+
+ /**
+ * HMAC-MD5 signer to build Message-Authenticator attribute
+ */
+ signer_t *signer;
+
+ /**
+ * random number generator for RADIUS request authenticator
+ */
+ rng_t *rng;
+
+ /**
+ * RADIUS secret
+ */
+ chunk_t secret;
+};
+
+METHOD(radius_socket_t, request, radius_message_t*,
+ private_radius_socket_t *this, radius_message_t *request)
+{
+ chunk_t data;
+ int i;
+
+ /* set Message Identifier */
+ request->set_identifier(request, this->identifier++);
+ /* sign the request */
+ request->sign(request, this->rng, this->signer);
+
+ data = request->get_encoding(request);
+ /* timeout after 2, 3, 4, 5 seconds */
+ for (i = 2; i <= 5; i++)
+ {
+ radius_message_t *response;
+ bool retransmit = FALSE;
+ struct timeval tv;
+ char buf[4096];
+ fd_set fds;
+ int res;
+
+ if (send(this->fd, data.ptr, data.len, 0) != data.len)
+ {
+ DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
+ return NULL;
+ }
+ tv.tv_sec = i;
+ tv.tv_usec = 0;
+
+ while (TRUE)
+ {
+ FD_ZERO(&fds);
+ FD_SET(this->fd, &fds);
+ res = select(this->fd + 1, &fds, NULL, NULL, &tv);
+ /* TODO: updated tv to time not waited. Linux does this for us. */
+ if (res < 0)
+ { /* failed */
+ DBG1(DBG_CFG, "waiting for RADIUS message failed: %s",
+ strerror(errno));
+ break;
+ }
+ if (res == 0)
+ { /* timeout */
+ DBG1(DBG_CFG, "retransmitting RADIUS message");
+ retransmit = TRUE;
+ break;
+ }
+ res = recv(this->fd, buf, sizeof(buf), MSG_DONTWAIT);
+ if (res <= 0)
+ {
+ DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
+ strerror(errno));
+ break;
+ }
+ response = radius_message_parse_response(chunk_create(buf, res));
+ if (response)
+ {
+ if (response->verify(response,
+ request->get_authenticator(request), this->secret,
+ this->hasher, this->signer))
+ {
+ return response;
+ }
+ response->destroy(response);
+ }
+ DBG1(DBG_CFG, "received invalid RADIUS message, ignored");
+ }
+ if (!retransmit)
+ {
+ break;
+ }
+ }
+ DBG1(DBG_CFG, "RADIUS server is not responding");
+ return NULL;
+}
+
+/**
+ * Decrypt a MS-MPPE-Send/Recv-Key
+ */
+static chunk_t decrypt_mppe_key(private_radius_socket_t *this, u_int16_t salt,
+ chunk_t C, radius_message_t *request)
+{
+ chunk_t A, R, P, seed;
+ u_char *c, *p;
+
+ /**
+ * From RFC2548 (encryption):
+ * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
+ * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
+ * . . .
+ * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
+ */
+
+ if (C.len % HASH_SIZE_MD5 || C.len < HASH_SIZE_MD5)
+ {
+ return chunk_empty;
+ }
+
+ A = chunk_create((u_char*)&salt, sizeof(salt));
+ R = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5);
+ P = chunk_alloca(C.len);
+ p = P.ptr;
+ c = C.ptr;
+
+ seed = chunk_cata("cc", R, A);
+
+ while (c < C.ptr + C.len)
+ {
+ /* b(i) = MD5(S + c(i-1)) */
+ this->hasher->get_hash(this->hasher, this->secret, NULL);
+ this->hasher->get_hash(this->hasher, seed, p);
+
+ /* p(i) = b(i) xor c(1) */
+ memxor(p, c, HASH_SIZE_MD5);
+
+ /* prepare next round */
+ seed = chunk_create(c, HASH_SIZE_MD5);
+ c += HASH_SIZE_MD5;
+ p += HASH_SIZE_MD5;
+ }
+
+ /* remove truncation, first byte is key length */
+ if (*P.ptr >= P.len)
+ { /* decryption failed? */
+ return chunk_empty;
+ }
+ return chunk_clone(chunk_create(P.ptr + 1, *P.ptr));
+}
+
+METHOD(radius_socket_t, decrypt_msk, chunk_t,
+ private_radius_socket_t *this, radius_message_t *request,
+ radius_message_t *response)
+{
+ struct {
+ u_int32_t id;
+ u_int8_t type;
+ u_int8_t length;
+ u_int16_t salt;
+ u_int8_t key[];
+ } __attribute__((packed)) *mppe_key;
+ enumerator_t *enumerator;
+ chunk_t data, send = chunk_empty, recv = chunk_empty;
+ int type;
+
+ enumerator = response->create_enumerator(response);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_VENDOR_SPECIFIC &&
+ data.len > sizeof(*mppe_key))
+ {
+ mppe_key = (void*)data.ptr;
+ if (ntohl(mppe_key->id) == VENDOR_ID_MICROSOFT &&
+ mppe_key->length == data.len - sizeof(mppe_key->id))
+ {
+ data = chunk_create(mppe_key->key, data.len - sizeof(*mppe_key));
+ if (mppe_key->type == MS_MPPE_SEND_KEY)
+ {
+ send = decrypt_mppe_key(this, mppe_key->salt, data, request);
+ }
+ if (mppe_key->type == MS_MPPE_RECV_KEY)
+ {
+ recv = decrypt_mppe_key(this, mppe_key->salt, data, request);
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (send.ptr && recv.ptr)
+ {
+ return chunk_cat("mm", recv, send);
+ }
+ chunk_clear(&send);
+ chunk_clear(&recv);
+ return chunk_empty;
+}
+
+METHOD(radius_socket_t, destroy, void,
+ private_radius_socket_t *this)
+{
+ DESTROY_IF(this->hasher);
+ DESTROY_IF(this->signer);
+ DESTROY_IF(this->rng);
+ close(this->fd);
+ free(this);
+}
+
+/**
+ * See header
+ */
+radius_socket_t *radius_socket_create(host_t *host, chunk_t secret)
+{
+ private_radius_socket_t *this;
+
+ INIT(this,
+ .public = {
+ .request = _request,
+ .decrypt_msk = _decrypt_msk,
+ .destroy = _destroy,
+ },
+ );
+
+ this->fd = socket(host->get_family(host), SOCK_DGRAM, IPPROTO_UDP);
+ if (this->fd < 0)
+ {
+ DBG1(DBG_CFG, "opening RADIUS socket failed: %s", strerror(errno));
+ free(this);
+ return NULL;
+ }
+ if (connect(this->fd, host->get_sockaddr(host),
+ *host->get_sockaddr_len(host)) < 0)
+ {
+ DBG1(DBG_CFG, "connecting RADIUS socket failed");
+ close(this->fd);
+ free(this);
+ return NULL;
+ }
+ this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
+ this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128);
+ this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!this->hasher || !this->signer || !this->rng)
+ {
+ DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required");
+ destroy(this);
+ return NULL;
+ }
+ this->secret = secret;
+ this->signer->set_key(this->signer, secret);
+ /* we use a random identifier, helps if we restart often */
+ this->identifier = random();
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/radius_socket.h b/src/libcharon/plugins/eap_radius/radius_socket.h
new file mode 100644
index 000000000..fe8491a8f
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/radius_socket.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 radius_socket radius_socket
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef RADIUS_SOCKET_H_
+#define RADIUS_SOCKET_H_
+
+typedef struct radius_socket_t radius_socket_t;
+
+#include "radius_message.h"
+
+#include <utils/host.h>
+
+/**
+ * RADIUS socket to a server.
+ */
+struct radius_socket_t {
+
+ /**
+ * Send a RADIUS request, wait for response.
+
+ * The socket fills in RADIUS Message identifier, builds a
+ * Request-Authenticator and calculates the Message-Authenticator
+ * attribute.
+ * The received response gets verified using the Response-Identifier
+ * and the Message-Authenticator attribute.
+ *
+ * @param request request message
+ * @return response message, NULL if timed out
+ */
+ radius_message_t* (*request)(radius_socket_t *this,
+ radius_message_t *request);
+
+ /**
+ * Decrypt the MSK encoded in a messages MS-MPPE-Send/Recv-Key.
+ *
+ * @param request associated RADIUS request message
+ * @param response RADIUS response message containing attributes
+ * @return allocated MSK, empty chunk if none found
+ */
+ chunk_t (*decrypt_msk)(radius_socket_t *this, radius_message_t *request,
+ radius_message_t *response);
+
+ /**
+ * Destroy a radius_socket_t.
+ */
+ void (*destroy)(radius_socket_t *this);
+};
+
+/**
+ * Create a radius_socket instance.
+ *
+ * @param host RADIUS server address to connect to
+ * @param secret RADIUS secret
+ */
+radius_socket_t *radius_socket_create(host_t *host, chunk_t secret);
+
+#endif /** RADIUS_SOCKET_H_ @}*/
diff --git a/src/libcharon/plugins/eap_sim/Makefile.in b/src/libcharon/plugins/eap_sim/Makefile.in
index 588965113..d0f44e925 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_sim/eap_sim_peer.c b/src/libcharon/plugins/eap_sim/eap_sim_peer.c
index 961cfd30d..a3506f4ba 100644
--- a/src/libcharon/plugins/eap_sim/eap_sim_peer.c
+++ b/src/libcharon/plugins/eap_sim/eap_sim_peer.c
@@ -484,7 +484,6 @@ static status_t process_notification(private_eap_sim_peer_t *this,
/* test success bit */
if (!(data.ptr[0] & 0x80))
{
- success = FALSE;
DBG1(DBG_IKE, "received EAP-SIM notification error '%N'",
simaka_notification_names, code);
}
diff --git a/src/libcharon/plugins/eap_sim_file/Makefile.in b/src/libcharon/plugins/eap_sim_file/Makefile.in
index 2d998dbcc..2aa0ac832 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in
index 6c44ea2bb..7d80f8019 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in
index 35d8e7c3b..fc26f4497 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/eap_simaka_sql/Makefile.am b/src/libcharon/plugins/eap_simaka_sql/Makefile.am
new file mode 100644
index 000000000..73768be0e
--- /dev/null
+++ b/src/libcharon/plugins/eap_simaka_sql/Makefile.am
@@ -0,0 +1,18 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${sysconfdir}\"
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-eap-simaka-sql.la
+else
+plugin_LTLIBRARIES = libstrongswan-eap-simaka-sql.la
+endif
+
+libstrongswan_eap_simaka_sql_la_SOURCES = \
+ eap_simaka_sql_plugin.h eap_simaka_sql_plugin.c \
+ eap_simaka_sql_card.h eap_simaka_sql_card.c \
+ eap_simaka_sql_provider.h eap_simaka_sql_provider.c
+
+libstrongswan_eap_simaka_sql_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/eap_simaka_sql/Makefile.in b/src/libcharon/plugins/eap_simaka_sql/Makefile.in
new file mode 100644
index 000000000..f2e82df0a
--- /dev/null
+++ b/src/libcharon/plugins/eap_simaka_sql/Makefile.in
@@ -0,0 +1,592 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
+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/eap_simaka_sql
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+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/with.m4 \
+ $(top_srcdir)/m4/macros/enable-disable.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+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__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
+libstrongswan_eap_simaka_sql_la_LIBADD =
+am_libstrongswan_eap_simaka_sql_la_OBJECTS = eap_simaka_sql_plugin.lo \
+ eap_simaka_sql_card.lo eap_simaka_sql_provider.lo
+libstrongswan_eap_simaka_sql_la_OBJECTS = \
+ $(am_libstrongswan_eap_simaka_sql_la_OBJECTS)
+libstrongswan_eap_simaka_sql_la_LINK = $(LIBTOOL) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) \
+ $(libstrongswan_eap_simaka_sql_la_LDFLAGS) $(LDFLAGS) -o $@
+@MONOLITHIC_FALSE@am_libstrongswan_eap_simaka_sql_la_rpath = -rpath \
+@MONOLITHIC_FALSE@ $(plugindir)
+@MONOLITHIC_TRUE@am_libstrongswan_eap_simaka_sql_la_rpath =
+DEFAULT_INCLUDES = -I.@am__isrc@
+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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libstrongswan_eap_simaka_sql_la_SOURCES)
+DIST_SOURCES = $(libstrongswan_eap_simaka_sql_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BTLIB = @BTLIB@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLIB = @DLLIB@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+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@
+MKDIR_P = @MKDIR_P@
+MYSQLCFLAG = @MYSQLCFLAG@
+MYSQLCONFIG = @MYSQLCONFIG@
+MYSQLLIB = @MYSQLLIB@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+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@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PTHREADLIB = @PTHREADLIB@
+RANLIB = @RANLIB@
+RTLIB = @RTLIB@
+RUBY = @RUBY@
+RUBYINCLUDE = @RUBYINCLUDE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKLIB = @SOCKLIB@
+STRIP = @STRIP@
+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_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_pkcs11 = @default_pkcs11@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gtk_CFLAGS = @gtk_CFLAGS@
+gtk_LIBS = @gtk_LIBS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+ipsecgid = @ipsecgid@
+ipsecgroup = @ipsecgroup@
+ipsecuid = @ipsecuid@
+ipsecuser = @ipsecuser@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libhydra_plugins = @libhydra_plugins@
+libstrongswan_plugins = @libstrongswan_plugins@
+linux_headers = @linux_headers@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nm_CFLAGS = @nm_CFLAGS@
+nm_LIBS = @nm_LIBS@
+nm_ca_dir = @nm_ca_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+plugindir = @plugindir@
+pluto_plugins = @pluto_plugins@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+random_device = @random_device@
+resolv_conf = @resolv_conf@
+routing_table = @routing_table@
+routing_table_prio = @routing_table_prio@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+strongswan_conf = @strongswan_conf@
+sysconfdir = @sysconfdir@
+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@
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${sysconfdir}\"
+@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-simaka-sql.la
+@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-simaka-sql.la
+libstrongswan_eap_simaka_sql_la_SOURCES = \
+ eap_simaka_sql_plugin.h eap_simaka_sql_plugin.c \
+ eap_simaka_sql_card.h eap_simaka_sql_card.c \
+ eap_simaka_sql_provider.h eap_simaka_sql_provider.c
+
+libstrongswan_eap_simaka_sql_la_LDFLAGS = -module -avoid-version
+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/eap_simaka_sql/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libcharon/plugins/eap_simaka_sql/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)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @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 " $(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)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libstrongswan-eap-simaka-sql.la: $(libstrongswan_eap_simaka_sql_la_OBJECTS) $(libstrongswan_eap_simaka_sql_la_DEPENDENCIES)
+ $(libstrongswan_eap_simaka_sql_la_LINK) $(am_libstrongswan_eap_simaka_sql_la_rpath) $(libstrongswan_eap_simaka_sql_la_OBJECTS) $(libstrongswan_eap_simaka_sql_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_simaka_sql_card.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_simaka_sql_plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_simaka_sql_provider.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ 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
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ 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"
+
+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:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+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 all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \
+ ctags 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 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/eap_simaka_sql/eap_simaka_sql_card.c b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c
new file mode 100644
index 000000000..b7590405f
--- /dev/null
+++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "eap_simaka_sql_card.h"
+
+#include <time.h>
+
+#include <daemon.h>
+
+typedef struct private_eap_simaka_sql_card_t private_eap_simaka_sql_card_t;
+
+/**
+ * Private data of an eap_simaka_sql_card_t object.
+ */
+struct private_eap_simaka_sql_card_t {
+
+ /**
+ * Public eap_simaka_sql_card_t interface.
+ */
+ eap_simaka_sql_card_t public;
+
+ /**
+ * Triplet/quintuplet database
+ */
+ database_t *db;
+
+ /**
+ * Remove used triplets/quintuplets from database
+ */
+ bool remove_used;
+};
+
+METHOD(sim_card_t, get_triplet, bool,
+ private_eap_simaka_sql_card_t *this, identification_t *id,
+ char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
+{
+ chunk_t sres_chunk, kc_chunk;
+ enumerator_t *query;
+ bool found = FALSE;
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%Y", id);
+ query = this->db->query(this->db,
+ "select sres, kc from triplets where rand = ? and id = ? "
+ "order by use limit 1",
+ DB_BLOB, chunk_create(rand, SIM_RAND_LEN), DB_TEXT, buf,
+ DB_BLOB, DB_BLOB);
+ if (query)
+ {
+ if (query->enumerate(query, &sres_chunk, &kc_chunk))
+ {
+ if (sres_chunk.len == SIM_SRES_LEN &&
+ kc_chunk.len == SIM_KC_LEN)
+ {
+ memcpy(sres, sres_chunk.ptr, SIM_SRES_LEN);
+ memcpy(kc, kc_chunk.ptr, SIM_KC_LEN);
+ found = TRUE;
+ }
+ }
+ query->destroy(query);
+ }
+ if (found)
+ {
+ if (this->remove_used)
+ {
+ this->db->execute(this->db, NULL,
+ "delete from triplets where id = ? and rand = ?",
+ DB_TEXT, buf, DB_BLOB, chunk_create(rand, SIM_RAND_LEN));
+ }
+ else
+ {
+ this->db->execute(this->db, NULL,
+ "update triplets set use = ? where id = ? and rand = ?",
+ DB_UINT, time(NULL), DB_TEXT, buf,
+ DB_BLOB, chunk_create(rand, SIM_RAND_LEN));
+ }
+ }
+ return found;
+}
+
+METHOD(sim_card_t, get_quintuplet, status_t,
+ private_eap_simaka_sql_card_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN],
+ char ik[AKA_IK_LEN], char res[AKA_RES_MAX], int *res_len)
+{
+ chunk_t ck_chunk, ik_chunk, res_chunk;
+ enumerator_t *query;
+ status_t found = FAILED;
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%Y", id);
+ query = this->db->query(this->db, "select ck, ik, res from quintuplets "
+ "where rand = ? and autn = ? and id = ? order by use limit 1",
+ DB_BLOB, chunk_create(rand, AKA_RAND_LEN),
+ DB_BLOB, chunk_create(autn, AKA_AUTN_LEN), DB_TEXT, buf,
+ DB_BLOB, DB_BLOB, DB_BLOB);
+ if (query)
+ {
+ if (query->enumerate(query, &ck_chunk, &ik_chunk, &res_chunk))
+ {
+ if (ck_chunk.len == AKA_CK_LEN &&
+ ik_chunk.len == AKA_IK_LEN &&
+ res_chunk.len <= AKA_RES_MAX)
+ {
+ memcpy(ck, ck_chunk.ptr, AKA_CK_LEN);
+ memcpy(ik, ik_chunk.ptr, AKA_IK_LEN);
+ memcpy(res, res_chunk.ptr, res_chunk.len);
+ *res_len = res_chunk.len;
+ found = SUCCESS;
+ }
+ }
+ query->destroy(query);
+ }
+ if (found == SUCCESS)
+ {
+ if (this->remove_used)
+ {
+ this->db->execute(this->db, NULL,
+ "delete from quintuplets where id = ? and rand = ?",
+ DB_TEXT, buf, DB_BLOB, chunk_create(rand, SIM_RAND_LEN));
+ }
+ else
+ {
+ this->db->execute(this->db, NULL,
+ "update quintuplets set use = ? where id = ? and rand = ?",
+ DB_UINT, time(NULL), DB_TEXT, buf,
+ DB_BLOB, chunk_create(rand, AKA_RAND_LEN));
+ }
+ }
+ return found;
+}
+
+METHOD(eap_simaka_sql_card_t, destroy, void,
+ private_eap_simaka_sql_card_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_simaka_sql_card_t *eap_simaka_sql_card_create(database_t *db,
+ bool remove_used)
+{
+ private_eap_simaka_sql_card_t *this;
+
+ INIT(this,
+ .public = {
+ .card = {
+ .get_triplet = _get_triplet,
+ .get_quintuplet = _get_quintuplet,
+ .resync = (void*)return_false,
+ .get_pseudonym = (void*)return_null,
+ .set_pseudonym = (void*)nop,
+ .get_reauth = (void*)return_null,
+ .set_reauth = (void*)nop,
+ },
+ .destroy = _destroy,
+ },
+ .db = db,
+ .remove_used = remove_used,
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.h b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.h
new file mode 100644
index 000000000..46b7de25e
--- /dev/null
+++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 eap_simaka_sql_card eap_simaka_sql_card
+ * @{ @ingroup eap_simaka_sql
+ */
+
+#ifndef EAP_SIMAKA_SQL_CARD_H_
+#define EAP_SIMAKA_SQL_CARD_H_
+
+#include <database/database.h>
+#include <sa/authenticators/eap/sim_manager.h>
+
+typedef struct eap_simaka_sql_card_t eap_simaka_sql_card_t;
+
+/**
+ * SIM card implementation using a triplet/quintuplet database backend.
+ */
+struct eap_simaka_sql_card_t {
+
+ /**
+ * Implements sim_card_t interface
+ */
+ sim_card_t card;
+
+ /**
+ * Destroy a eap_simaka_sql_card_t.
+ */
+ void (*destroy)(eap_simaka_sql_card_t *this);
+};
+
+/**
+ * Create a eap_simaka_sql_card instance.
+ *
+ * @param db triplet/quintuplet database
+ * @param remove_used TRUE to remove used triplets/quintuplets from db
+ */
+eap_simaka_sql_card_t *eap_simaka_sql_card_create(database_t *db,
+ bool remove_used);
+
+#endif /** EAP_SIMAKA_SQL_CARD_H_ @}*/
diff --git a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.c b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.c
new file mode 100644
index 000000000..0f5319792
--- /dev/null
+++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "eap_simaka_sql_plugin.h"
+#include "eap_simaka_sql_card.h"
+#include "eap_simaka_sql_provider.h"
+
+#include <daemon.h>
+
+typedef struct private_eap_simaka_sql_t private_eap_simaka_sql_t;
+
+/**
+ * Private data of an eap_simaka_sql_t object.
+ */
+struct private_eap_simaka_sql_t {
+
+ /**
+ * Public eap_simaka_sql_plugin_t interface.
+ */
+ eap_simaka_sql_plugin_t public;
+
+ /**
+ * (U)SIM card
+ */
+ eap_simaka_sql_card_t *card;
+
+ /**
+ * (U)SIM provider
+ */
+ eap_simaka_sql_provider_t *provider;
+
+ /**
+ * Database with triplets/quintuplets
+ */
+ database_t *db;
+};
+
+METHOD(plugin_t, destroy, void,
+ private_eap_simaka_sql_t *this)
+{
+ charon->sim->remove_card(charon->sim, &this->card->card);
+ charon->sim->remove_provider(charon->sim, &this->provider->provider);
+ this->card->destroy(this->card);
+ this->provider->destroy(this->provider);
+ this->db->destroy(this->db);
+ free(this);
+}
+
+/**
+ * See header
+ */
+plugin_t *eap_simaka_sql_plugin_create()
+{
+ private_eap_simaka_sql_t *this;
+ database_t *db;
+ bool remove_used;
+ char *uri;
+
+ uri = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-simaka-sql.database", NULL);
+ if (!uri)
+ {
+ DBG1(DBG_CFG, "eap-simaka-sql database URI missing");
+ return NULL;
+ }
+ db = lib->db->create(lib->db, uri);
+ if (!db)
+ {
+ DBG1(DBG_CFG, "opening eap-simaka-sql database failed");
+ return NULL;
+ }
+ remove_used = lib->settings->get_bool(lib->settings,
+ "charon.plugins.eap-simaka-sql.remove_used", FALSE);
+
+ INIT(this,
+ .public.plugin = {
+ .destroy = _destroy,
+ },
+ .db = db,
+ .provider = eap_simaka_sql_provider_create(db, remove_used),
+ .card = eap_simaka_sql_card_create(db, remove_used),
+ );
+
+ charon->sim->add_card(charon->sim, &this->card->card);
+ charon->sim->add_provider(charon->sim, &this->provider->provider);
+
+ return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.h b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.h
new file mode 100644
index 000000000..3064580bf
--- /dev/null
+++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 eap_simaka_sql eap_simaka_sql
+ * @ingroup cplugins
+ *
+ * @defgroup eap_simaka_sql_plugin eap_simaka_sql_plugin
+ * @{ @ingroup eap_simaka_sql
+ */
+
+#ifndef EAP_SIMAKA_SQL_PLUGIN_H_
+#define EAP_SIMAKA_SQL_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct eap_simaka_sql_plugin_t eap_simaka_sql_plugin_t;
+
+/**
+ * Plugin to provide SIM/AKA cards/providers using triplets from a database.
+ */
+struct eap_simaka_sql_plugin_t {
+
+ /**
+ * Implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** EAP_SIMAKA_SQL_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_provider.c b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_provider.c
new file mode 100644
index 000000000..73cccf549
--- /dev/null
+++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_provider.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "eap_simaka_sql_provider.h"
+
+#include <time.h>
+
+#include <daemon.h>
+
+typedef struct private_eap_simaka_sql_provider_t private_eap_simaka_sql_provider_t;
+
+/**
+ * Private data of an eap_simaka_sql_provider_t object.
+ */
+struct private_eap_simaka_sql_provider_t {
+
+ /**
+ * Public eap_simaka_sql_provider_t interface.
+ */
+ eap_simaka_sql_provider_t public;
+
+ /**
+ * Triplet/quintuplet database
+ */
+ database_t *db;
+
+ /**
+ * Remove used triplets/quintuplets from database
+ */
+ bool remove_used;
+};
+
+METHOD(sim_provider_t, get_triplet, bool,
+ private_eap_simaka_sql_provider_t *this, identification_t *id,
+ char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
+{
+ chunk_t rand_chunk, sres_chunk, kc_chunk;
+ enumerator_t *query;
+ bool found = FALSE;
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%Y", id);
+ query = this->db->query(this->db,
+ "select rand, sres, kc from triplets where id = ? order by use",
+ DB_TEXT, buf, DB_BLOB, DB_BLOB, DB_BLOB);
+ if (query)
+ {
+ if (query->enumerate(query, &rand_chunk, &sres_chunk, &kc_chunk))
+ {
+ if (rand_chunk.len == SIM_RAND_LEN &&
+ sres_chunk.len == SIM_SRES_LEN &&
+ kc_chunk.len == SIM_KC_LEN)
+ {
+ memcpy(rand, rand_chunk.ptr, SIM_RAND_LEN);
+ memcpy(sres, sres_chunk.ptr, SIM_SRES_LEN);
+ memcpy(kc, kc_chunk.ptr, SIM_KC_LEN);
+ found = TRUE;
+ }
+ }
+ query->destroy(query);
+ }
+ if (found)
+ {
+ if (this->remove_used)
+ {
+ this->db->execute(this->db, NULL,
+ "delete from triplets where id = ? and rand = ?",
+ DB_TEXT, buf, DB_BLOB, chunk_create(rand, SIM_RAND_LEN));
+ }
+ else
+ {
+ this->db->execute(this->db, NULL,
+ "update triplets set use = ? where id = ? and rand = ?",
+ DB_UINT, time(NULL), DB_TEXT, buf,
+ DB_BLOB, chunk_create(rand, SIM_RAND_LEN));
+ }
+ }
+ return found;
+}
+
+METHOD(sim_provider_t, get_quintuplet, bool,
+ private_eap_simaka_sql_provider_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len,
+ char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN])
+{
+ chunk_t rand_chunk, xres_chunk, ck_chunk, ik_chunk, autn_chunk;
+ enumerator_t *query;
+ bool found = FALSE;
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%Y", id);
+ query = this->db->query(this->db, "select rand, res, ck, ik, autn "
+ "from quintuplets where id = ? order by use", DB_TEXT, buf,
+ DB_BLOB, DB_BLOB, DB_BLOB, DB_BLOB, DB_BLOB);
+ if (query)
+ {
+ if (query->enumerate(query, &rand_chunk, &xres_chunk,
+ &ck_chunk, &ik_chunk, &autn_chunk))
+ {
+ if (rand_chunk.len == AKA_RAND_LEN &&
+ xres_chunk.len <= AKA_RES_MAX &&
+ ck_chunk.len == AKA_CK_LEN &&
+ ik_chunk.len == AKA_IK_LEN &&
+ autn_chunk.len == AKA_AUTN_LEN)
+ {
+ memcpy(rand, rand_chunk.ptr, AKA_RAND_LEN);
+ memcpy(xres, xres_chunk.ptr, xres_chunk.len);
+ *xres_len = xres_chunk.len;
+ memcpy(ck, ck_chunk.ptr, AKA_CK_LEN);
+ memcpy(ik, ik_chunk.ptr, AKA_IK_LEN);
+ memcpy(autn, autn_chunk.ptr, AKA_AUTN_LEN);
+ found = TRUE;
+ }
+ }
+ query->destroy(query);
+ }
+ if (found)
+ {
+ if (this->remove_used)
+ {
+ this->db->execute(this->db, NULL,
+ "delete from quintuplets where id = ? and rand = ?",
+ DB_TEXT, buf, DB_BLOB, chunk_create(rand, SIM_RAND_LEN));
+ }
+ else
+ {
+ this->db->execute(this->db, NULL,
+ "update quintuplets set use = ? where id = ? and rand = ?",
+ DB_UINT, time(NULL), DB_TEXT, buf,
+ DB_BLOB, chunk_create(rand, AKA_RAND_LEN));
+ }
+ }
+ return found;
+}
+
+METHOD(eap_simaka_sql_provider_t, destroy, void,
+ private_eap_simaka_sql_provider_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_simaka_sql_provider_t *eap_simaka_sql_provider_create(database_t *db,
+ bool remove_used)
+{
+ private_eap_simaka_sql_provider_t *this;
+
+ INIT(this,
+ .public = {
+ .provider = {
+ .get_triplet = _get_triplet,
+ .get_quintuplet = _get_quintuplet,
+ .resync = (void*)return_false,
+ .is_pseudonym = (void*)return_null,
+ .gen_pseudonym = (void*)return_null,
+ .is_reauth = (void*)return_null,
+ .gen_reauth = (void*)return_null,
+ },
+ .destroy = _destroy,
+ },
+ .db = db,
+ .remove_used = remove_used,
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_provider.h b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_provider.h
new file mode 100644
index 000000000..ecb0c8cb0
--- /dev/null
+++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_provider.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 eap_simaka_sql_provider eap_simaka_sql_provider
+ * @{ @ingroup eap_simaka_sql
+ */
+
+#ifndef EAP_SIMAKA_SQL_PROVIDER_H_
+#define EAP_SIMAKA_SQL_PROVIDER_H_
+
+#include <database/database.h>
+#include <sa/authenticators/eap/sim_manager.h>
+
+typedef struct eap_simaka_sql_provider_t eap_simaka_sql_provider_t;
+
+/**
+ * SIM provider implementation using a triplet/quintuplet database backend.
+ */
+struct eap_simaka_sql_provider_t {
+
+ /**
+ * Implements sim_provider_t interface
+ */
+ sim_provider_t provider;
+
+ /**
+ * Destroy a eap_simaka_sql_provider_t.
+ */
+ void (*destroy)(eap_simaka_sql_provider_t *this);
+};
+
+/**
+ * Create a eap_simaka_sql_provider instance.
+ *
+ * @param db triplet/quintuplet database
+ * @param remove_used TRUE to remove used triplets/quintuplets from db
+ */
+eap_simaka_sql_provider_t *eap_simaka_sql_provider_create(database_t *db,
+ bool remove_used);
+
+#endif /** EAP_SIMAKA_SQL_PROVIDER_H_ @}*/
diff --git a/src/libcharon/plugins/farp/Makefile.in b/src/libcharon/plugins/farp/Makefile.in
index 20ac77080..47952b99e 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/farp/farp_spoofer.c b/src/libcharon/plugins/farp/farp_spoofer.c
index 29e64e32d..20bb44fd3 100644
--- a/src/libcharon/plugins/farp/farp_spoofer.c
+++ b/src/libcharon/plugins/farp/farp_spoofer.c
@@ -156,8 +156,8 @@ farp_spoofer_t *farp_spoofer_create(farp_listener_t *listener)
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, offsetof(arp_t, opcode)),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REQUEST, 0, 3),
BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 28, 0, 1),
- BPF_STMT(BPF_RET+BPF_A, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, sizeof(arp_t), 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, sizeof(arp_t)),
BPF_STMT(BPF_RET+BPF_K, 0),
};
struct sock_fprog arp_request_filter = {
diff --git a/src/libcharon/plugins/ha/Makefile.am b/src/libcharon/plugins/ha/Makefile.am
index 74fe1f4c7..0df1b8d91 100644
--- a/src/libcharon/plugins/ha/Makefile.am
+++ b/src/libcharon/plugins/ha/Makefile.am
@@ -17,9 +17,11 @@ libstrongswan_ha_la_SOURCES = \
ha_tunnel.h ha_tunnel.c \
ha_dispatcher.h ha_dispatcher.c \
ha_segments.h ha_segments.c \
+ ha_cache.h ha_cache.c \
ha_kernel.h ha_kernel.c \
ha_ctl.h ha_ctl.c \
ha_ike.h ha_ike.c \
- ha_child.h ha_child.c
+ ha_child.h ha_child.c \
+ ha_attribute.h ha_attribute.c
libstrongswan_ha_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/ha/Makefile.in b/src/libcharon/plugins/ha/Makefile.in
index c60d3bf56..5ca9b464b 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -76,7 +76,8 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
libstrongswan_ha_la_LIBADD =
am_libstrongswan_ha_la_OBJECTS = ha_plugin.lo ha_message.lo \
ha_socket.lo ha_tunnel.lo ha_dispatcher.lo ha_segments.lo \
- ha_kernel.lo ha_ctl.lo ha_ike.lo ha_child.lo
+ ha_cache.lo ha_kernel.lo ha_ctl.lo ha_ike.lo ha_child.lo \
+ ha_attribute.lo
libstrongswan_ha_la_OBJECTS = $(am_libstrongswan_ha_la_OBJECTS)
libstrongswan_ha_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@@ -269,10 +270,12 @@ libstrongswan_ha_la_SOURCES = \
ha_tunnel.h ha_tunnel.c \
ha_dispatcher.h ha_dispatcher.c \
ha_segments.h ha_segments.c \
+ ha_cache.h ha_cache.c \
ha_kernel.h ha_kernel.c \
ha_ctl.h ha_ctl.c \
ha_ike.h ha_ike.c \
- ha_child.h ha_child.c
+ ha_child.h ha_child.c \
+ ha_attribute.h ha_attribute.c
libstrongswan_ha_la_LDFLAGS = -module -avoid-version
all: all-am
@@ -358,6 +361,8 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_attribute.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_child.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_ctl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_dispatcher.Plo@am__quote@
diff --git a/src/libcharon/plugins/ha/ha_attribute.c b/src/libcharon/plugins/ha/ha_attribute.c
new file mode 100644
index 000000000..b08abe1a9
--- /dev/null
+++ b/src/libcharon/plugins/ha/ha_attribute.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "ha_attribute.h"
+
+#include <utils/linked_list.h>
+#include <threading/mutex.h>
+
+typedef struct private_ha_attribute_t private_ha_attribute_t;
+
+/**
+ * Private data of an ha_attribute_t object.
+ */
+struct private_ha_attribute_t {
+
+ /**
+ * Public ha_attribute_t interface.
+ */
+ ha_attribute_t public;
+
+ /**
+ * List of pools, pool_t
+ */
+ linked_list_t *pools;
+
+ /**
+ * Mutex to lock mask
+ */
+ mutex_t *mutex;
+
+ /**
+ * Kernel helper
+ */
+ ha_kernel_t *kernel;
+
+ /**
+ * Segment responsibility
+ */
+ ha_segments_t *segments;
+};
+
+/**
+ * In-memory pool.
+ */
+typedef struct {
+ /** name of the pool */
+ char *name;
+ /** base address of pool */
+ host_t *base;
+ /** total number of addresses in this pool */
+ int size;
+ /** bitmask for address usage */
+ u_char *mask;
+} pool_t;
+
+/**
+ * Clean up a pool entry
+ */
+static void pool_destroy(pool_t *pool)
+{
+ pool->base->destroy(pool->base);
+ free(pool->name);
+ free(pool->mask);
+ free(pool);
+}
+
+/**
+ * convert a pool offset to an address
+ */
+static host_t* offset2host(pool_t *pool, int offset)
+{
+ chunk_t addr;
+ host_t *host;
+ u_int32_t *pos;
+
+ if (offset > pool->size)
+ {
+ return NULL;
+ }
+
+ addr = chunk_clone(pool->base->get_address(pool->base));
+ if (pool->base->get_family(pool->base) == AF_INET6)
+ {
+ pos = (u_int32_t*)(addr.ptr + 12);
+ }
+ else
+ {
+ pos = (u_int32_t*)addr.ptr;
+ }
+ *pos = htonl(offset + ntohl(*pos));
+ host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
+ free(addr.ptr);
+ return host;
+}
+
+/**
+ * convert a host to a pool offset
+ */
+static int host2offset(pool_t *pool, host_t *addr)
+{
+ chunk_t host, base;
+ u_int32_t hosti, basei;
+
+ if (addr->get_family(addr) != pool->base->get_family(pool->base))
+ {
+ return -1;
+ }
+ host = addr->get_address(addr);
+ base = pool->base->get_address(pool->base);
+ if (addr->get_family(addr) == AF_INET6)
+ {
+ /* only look at last /32 block */
+ if (!memeq(host.ptr, base.ptr, 12))
+ {
+ return -1;
+ }
+ host = chunk_skip(host, 12);
+ base = chunk_skip(base, 12);
+ }
+ hosti = ntohl(*(u_int32_t*)(host.ptr));
+ basei = ntohl(*(u_int32_t*)(base.ptr));
+ if (hosti > basei + pool->size)
+ {
+ return -1;
+ }
+ return hosti - basei;
+}
+
+/**
+ * Find a pool by its name
+ */
+static pool_t* get_pool(private_ha_attribute_t *this, char *name)
+{
+ enumerator_t *enumerator;
+ pool_t *pool, *found = NULL;
+
+ enumerator = this->pools->create_enumerator(this->pools);
+ while (enumerator->enumerate(enumerator, &pool))
+ {
+ if (streq(name, pool->name))
+ {
+ found = pool;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+/**
+ * Check if we are responsible for a bit in our bitmask
+ */
+static bool responsible_for(private_ha_attribute_t *this, int bit)
+{
+ u_int segment;
+
+ segment = this->kernel->get_segment_int(this->kernel, bit);
+ return this->segments->is_active(this->segments, segment);
+}
+
+METHOD(attribute_provider_t, acquire_address, host_t*,
+ private_ha_attribute_t *this, char *name, identification_t *id,
+ host_t *requested)
+{
+ pool_t *pool;
+ int offset = -1, byte, bit;
+ host_t *address;
+
+ this->mutex->lock(this->mutex);
+ pool = get_pool(this, name);
+ if (pool)
+ {
+ for (byte = 0; byte < pool->size / 8; byte++)
+ {
+ if (pool->mask[byte] != 0xFF)
+ {
+ for (bit = 0; bit < 8; bit++)
+ {
+ if (!(pool->mask[byte] & 1 << bit) &&
+ responsible_for(this, bit))
+ {
+ offset = byte * 8 + bit;
+ pool->mask[byte] |= 1 << bit;
+ break;
+ }
+ }
+ }
+ if (offset != -1)
+ {
+ break;
+ }
+ }
+ if (offset == -1)
+ {
+ DBG1(DBG_CFG, "no address left in HA pool '%s' belonging to"
+ "a responsible segment", name);
+ }
+ }
+ this->mutex->unlock(this->mutex);
+ if (offset != -1)
+ {
+ address = offset2host(pool, offset);
+ DBG1(DBG_CFG, "acquired address %H from HA pool '%s'", address, name);
+ return address;
+ }
+ return NULL;
+}
+
+METHOD(attribute_provider_t, release_address, bool,
+ private_ha_attribute_t *this, char *name, host_t *address,
+ identification_t *id)
+{
+ pool_t *pool;
+ int offset;
+ bool found = FALSE;
+
+ this->mutex->lock(this->mutex);
+ pool = get_pool(this, name);
+ if (pool)
+ {
+ offset = host2offset(pool, address);
+ if (offset > 0 && offset < pool->size)
+ {
+ pool->mask[offset / 8] &= ~(1 << (offset % 8));
+ DBG1(DBG_CFG, "released address %H to HA pool '%s'", address, name);
+ found = TRUE;
+ }
+ }
+ this->mutex->unlock(this->mutex);
+ return found;
+}
+
+METHOD(ha_attribute_t, reserve, void,
+ private_ha_attribute_t *this, char *name, host_t *address)
+{
+ pool_t *pool;
+ int offset;
+
+ this->mutex->lock(this->mutex);
+ pool = get_pool(this, name);
+ if (pool)
+ {
+ offset = host2offset(pool, address);
+ if (offset > 0 && offset < pool->size)
+ {
+ pool->mask[offset / 8] |= 1 << (offset % 8);
+ DBG1(DBG_CFG, "reserved address %H in HA pool '%s'", address, name);
+ }
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(ha_attribute_t, destroy, void,
+ private_ha_attribute_t *this)
+{
+ this->pools->destroy_function(this->pools, (void*)pool_destroy);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/**
+ * Load the configured pools.
+ */
+static void load_pools(private_ha_attribute_t *this)
+{
+ enumerator_t *enumerator;
+ char *name, *net, *bits;
+ host_t *base;
+ int mask, maxbits;
+ pool_t *pool;
+
+ enumerator = lib->settings->create_key_value_enumerator(lib->settings,
+ "charon.plugins.ha.pools");
+ while (enumerator->enumerate(enumerator, &name, &net))
+ {
+ net = strdup(net);
+ bits = strchr(net, '/');
+ if (!bits)
+ {
+ DBG1(DBG_CFG, "invalid HA pool '%s' subnet, skipped", name);
+ free(net);
+ continue;
+ }
+ *bits++ = '\0';
+
+ base = host_create_from_string(net, 0);
+ mask = atoi(bits);
+ free(net);
+ if (!base || !mask)
+ {
+ DESTROY_IF(base);
+ DBG1(DBG_CFG, "invalid HA pool '%s', skipped", name);
+ continue;
+ }
+ maxbits = base->get_family(base) == AF_INET ? 32 : 128;
+ mask = maxbits - mask;
+ if (mask > 24)
+ {
+ mask = 24;
+ DBG1(DBG_CFG, "size of HA pool '%s' limited to /%d",
+ name, maxbits - mask);
+ }
+ if (mask < 3)
+ {
+ DBG1(DBG_CFG, "HA pool '%s' too small, skipped", name);
+ base->destroy(base);
+ continue;
+ }
+
+ INIT(pool,
+ .name = strdup(name),
+ .base = base,
+ .size = (1 << mask),
+ );
+ pool->mask = calloc(pool->size / 8, 1);
+ /* do not use first/last address of pool */
+ pool->mask[0] |= 0x01;
+ pool->mask[pool->size / 8 - 1] |= 0x80;
+
+ DBG1(DBG_CFG, "loaded HA pool '%s' %H/%d (%d addresses)",
+ pool->name, pool->base, maxbits - mask, pool->size - 2);
+ this->pools->insert_last(this->pools, pool);
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * See header
+ */
+ha_attribute_t *ha_attribute_create(ha_kernel_t *kernel, ha_segments_t *segments)
+{
+ private_ha_attribute_t *this;
+
+ INIT(this,
+ .public = {
+ .provider = {
+ .acquire_address = _acquire_address,
+ .release_address = _release_address,
+ .create_attribute_enumerator = enumerator_create_empty,
+ },
+ .reserve = _reserve,
+ .destroy = _destroy,
+ },
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .pools = linked_list_create(),
+ .kernel = kernel,
+ .segments = segments,
+ );
+
+ load_pools(this);
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/ha/ha_attribute.h b/src/libcharon/plugins/ha/ha_attribute.h
new file mode 100644
index 000000000..d1e4f5e89
--- /dev/null
+++ b/src/libcharon/plugins/ha/ha_attribute.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 ha_attribute ha_attribute
+ * @{ @ingroup ha
+ */
+
+#ifndef HA_ATTRIBUTE_H_
+#define HA_ATTRIBUTE_H_
+
+#include "ha_kernel.h"
+#include "ha_segments.h"
+
+#include <attributes/attribute_provider.h>
+
+typedef struct ha_attribute_t ha_attribute_t;
+
+/**
+ * A HA enabled in memory address pool attribute provider.
+ */
+struct ha_attribute_t {
+
+ /**
+ * Implements attribute provider interface.
+ */
+ attribute_provider_t provider;
+
+ /**
+ * Reserve an address for a passive IKE_SA.
+ *
+ * @param name pool name to reserve address in
+ * @param address address to reserve
+ */
+ void (*reserve)(ha_attribute_t *this, char *name, host_t *address);
+
+ /**
+ * Destroy a ha_attribute_t.
+ */
+ void (*destroy)(ha_attribute_t *this);
+};
+
+/**
+ * Create a ha_attribute instance.
+ */
+ha_attribute_t *ha_attribute_create(ha_kernel_t *kernel, ha_segments_t *segments);
+
+#endif /** HA_ATTRIBUTE_H_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_cache.c b/src/libcharon/plugins/ha/ha_cache.c
new file mode 100644
index 000000000..1ebc33ca4
--- /dev/null
+++ b/src/libcharon/plugins/ha/ha_cache.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "ha_cache.h"
+
+#include <utils/hashtable.h>
+#include <utils/linked_list.h>
+#include <threading/mutex.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_ha_cache_t private_ha_cache_t;
+
+/**
+ * Private data of an ha_cache_t object.
+ */
+struct private_ha_cache_t {
+
+ /**
+ * Public ha_cache_t interface.
+ */
+ ha_cache_t public;
+
+ /**
+ * Kernel helper functions
+ */
+ ha_kernel_t *kernel;
+
+ /**
+ * Socket to send sync messages over
+ */
+ ha_socket_t *socket;
+
+ /**
+ * Total number of segments
+ */
+ u_int count;
+
+ /**
+ * cached entries (ike_sa_t, entry_t)
+ */
+ hashtable_t *cache;
+
+ /**
+ * Mutex to lock cache
+ */
+ mutex_t *mutex;
+};
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(void *key)
+{
+ return (uintptr_t)key;
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(void *a, void *b)
+{
+ return a == b;
+}
+
+/**
+ * Cache entry for an IKE_SA
+ */
+typedef struct {
+ /* segment this entry is associate to */
+ u_int segment;
+ /* ADD message */
+ ha_message_t *add;
+ /* list of updates UPDATE message */
+ linked_list_t *updates;
+ /* last initiator mid */
+ ha_message_t *midi;
+ /* last responder mid */
+ ha_message_t *midr;
+} entry_t;
+
+/**
+ * Create a entry with an add message
+ */
+static entry_t *entry_create(ha_message_t *add)
+{
+ entry_t *entry;
+
+ INIT(entry,
+ .add = add,
+ .updates = linked_list_create(),
+ );
+ return entry;
+}
+
+/**
+ * clean up a entry
+ */
+static void entry_destroy(entry_t *entry)
+{
+ entry->updates->destroy_offset(entry->updates,
+ offsetof(ha_message_t, destroy));
+ entry->add->destroy(entry->add);
+ DESTROY_IF(entry->midi);
+ DESTROY_IF(entry->midr);
+ free(entry);
+}
+
+METHOD(ha_cache_t, cache, void,
+ private_ha_cache_t *this, ike_sa_t *ike_sa, ha_message_t *message)
+{
+ entry_t *entry;
+
+ this->mutex->lock(this->mutex);
+ switch (message->get_type(message))
+ {
+ case HA_IKE_ADD:
+ entry = entry_create(message);
+ entry = this->cache->put(this->cache, ike_sa, entry);
+ if (entry)
+ {
+ entry_destroy(entry);
+ }
+ break;
+ case HA_IKE_UPDATE:
+ entry = this->cache->get(this->cache, ike_sa);
+ if (entry)
+ {
+ entry->segment = this->kernel->get_segment(this->kernel,
+ ike_sa->get_other_host(ike_sa));
+ entry->updates->insert_last(entry->updates, message);
+ break;
+ }
+ message->destroy(message);
+ break;
+ case HA_IKE_MID_INITIATOR:
+ entry = this->cache->get(this->cache, ike_sa);
+ if (entry)
+ {
+ DESTROY_IF(entry->midi);
+ entry->midi = message;
+ break;
+ }
+ message->destroy(message);
+ break;
+ case HA_IKE_MID_RESPONDER:
+ entry = this->cache->get(this->cache, ike_sa);
+ if (entry)
+ {
+ DESTROY_IF(entry->midr);
+ entry->midr = message;
+ break;
+ }
+ message->destroy(message);
+ break;
+ case HA_IKE_DELETE:
+ entry = this->cache->remove(this->cache, ike_sa);
+ if (entry)
+ {
+ entry_destroy(entry);
+ }
+ message->destroy(message);
+ break;
+ default:
+ message->destroy(message);
+ break;
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(ha_cache_t, delete_, void,
+ private_ha_cache_t *this, ike_sa_t *ike_sa)
+{
+ entry_t *entry;
+
+ entry = this->cache->remove(this->cache, ike_sa);
+ if (entry)
+ {
+ entry_destroy(entry);
+ }
+}
+
+/**
+ * Rekey all children of an IKE_SA
+ */
+static status_t rekey_children(ike_sa_t *ike_sa)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ status_t status = SUCCESS;
+
+ iterator = ike_sa->create_child_sa_iterator(ike_sa);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ DBG1(DBG_CFG, "resyncing CHILD_SA");
+ status = ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
+ child_sa->get_spi(child_sa, TRUE));
+ if (status == DESTROY_ME)
+ {
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return status;
+}
+
+/**
+ * Trigger rekeying of CHILD_SA in segment
+ */
+static void rekey_segment(private_ha_cache_t *this, u_int segment)
+{
+ ike_sa_t *ike_sa;
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ ike_sa_id_t *id;
+
+ list = linked_list_create();
+
+ enumerator = charon->ike_sa_manager->create_enumerator(
+ charon->ike_sa_manager);
+ while (enumerator->enumerate(enumerator, &ike_sa))
+ {
+ if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
+ this->kernel->get_segment(this->kernel,
+ ike_sa->get_other_host(ike_sa)) == segment)
+ {
+ id = ike_sa->get_id(ike_sa);
+ list->insert_last(list, id->clone(id));
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ while (list->remove_last(list, (void**)&id) == SUCCESS)
+ {
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+ if (ike_sa)
+ {
+ if (rekey_children(ike_sa) != DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin(
+ charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
+ }
+ }
+ id->destroy(id);
+ }
+ list->destroy(list);
+}
+
+METHOD(ha_cache_t, resync, void,
+ private_ha_cache_t *this, u_int segment)
+{
+ enumerator_t *enumerator, *updates;
+ ike_sa_t *ike_sa;
+ entry_t *entry;
+ ha_message_t *message;
+
+ DBG1(DBG_CFG, "resyncing HA segment %d", segment);
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->cache->create_enumerator(this->cache);
+ while (enumerator->enumerate(enumerator, &ike_sa, &entry))
+ {
+ if (entry->segment == segment)
+ {
+ this->socket->push(this->socket, entry->add);
+ updates = entry->updates->create_enumerator(entry->updates);
+ while (updates->enumerate(updates, &message))
+ {
+ this->socket->push(this->socket, message);
+ }
+ updates->destroy(updates);
+ if (entry->midi)
+ {
+ this->socket->push(this->socket, entry->midi);
+ }
+ if (entry->midr)
+ {
+ this->socket->push(this->socket, entry->midr);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+
+ rekey_segment(this, segment);
+}
+
+/**
+ * Request a resync of all segments
+ */
+static job_requeue_t request_resync(private_ha_cache_t *this)
+{
+ ha_message_t *message;
+ int i;
+
+ DBG1(DBG_CFG, "requesting HA resynchronization");
+
+ message = ha_message_create(HA_RESYNC);
+ for (i = 1; i <= this->count; i++)
+ {
+ message->add_attribute(message, HA_SEGMENT, i);
+ }
+ this->socket->push(this->socket, message);
+ message->destroy(message);
+ return JOB_REQUEUE_NONE;
+}
+
+METHOD(ha_cache_t, destroy, void,
+ private_ha_cache_t *this)
+{
+ this->cache->destroy(this->cache);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/**
+ * See header
+ */
+ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
+ bool sync, u_int count)
+{
+ private_ha_cache_t *this;
+
+ INIT(this,
+ .public = {
+ .cache = _cache,
+ .delete = _delete_,
+ .resync = _resync,
+ .destroy = _destroy,
+ },
+ .count = count,
+ .kernel = kernel,
+ .socket = socket,
+ .cache = hashtable_create(hash, equals, 8),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ if (sync)
+ {
+ /* request a resync as soon as we are up */
+ charon->scheduler->schedule_job(charon->scheduler, (job_t*)
+ callback_job_create((callback_job_cb_t)request_resync,
+ this, NULL, NULL), 1);
+ }
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/ha/ha_cache.h b/src/libcharon/plugins/ha/ha_cache.h
new file mode 100644
index 000000000..39f1947a8
--- /dev/null
+++ b/src/libcharon/plugins/ha/ha_cache.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 ha_cache ha_cache
+ * @{ @ingroup ha
+ */
+
+#ifndef HA_CACHE_H_
+#define HA_CACHE_H_
+
+typedef struct ha_cache_t ha_cache_t;
+
+#include "ha_message.h"
+#include "ha_kernel.h"
+#include "ha_socket.h"
+
+#include <utils/enumerator.h>
+
+#include <sa/ike_sa.h>
+
+/**
+ * HA message caching facility, allows reintegration of new nodes.
+ */
+struct ha_cache_t {
+
+ /**
+ * Cache an IKE specific message.
+ *
+ * @param ike_sa associated IKE_SA
+ * @param message message to cache
+ */
+ void (*cache)(ha_cache_t *this, ike_sa_t *ike_sa, ha_message_t *message);
+
+ /**
+ * Delete a cache entry for an IKE_SA.
+ *
+ * @param ike_sa cache entry to delete
+ */
+ void (*delete)(ha_cache_t *this, ike_sa_t *ike_sa);
+
+ /**
+ * Resync a segment to the node using the cached messages.
+ *
+ * @param segment segment to resync
+ */
+ void (*resync)(ha_cache_t *this, u_int segment);
+
+ /**
+ * Destroy a ha_cache_t.
+ */
+ void (*destroy)(ha_cache_t *this);
+};
+
+/**
+ * Create a ha_cache instance.
+ *
+ * @param kernel kernel helper
+ * @param socket socket to send resync messages
+ * @param resync request a resync during startup?
+ * @param count total number of segments
+ */
+ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
+ bool resync, u_int count);
+
+#endif /** HA_CACHE_H_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_child.c b/src/libcharon/plugins/ha/ha_child.c
index 2eb8e27f6..1a9425423 100644
--- a/src/libcharon/plugins/ha/ha_child.c
+++ b/src/libcharon/plugins/ha/ha_child.c
@@ -36,22 +36,30 @@ struct private_ha_child_t {
* tunnel securing sync messages
*/
ha_tunnel_t *tunnel;
+
+ /**
+ * Segment handling
+ */
+ ha_segments_t *segments;
+
+ /**
+ * Kernel helper
+ */
+ ha_kernel_t *kernel;
};
-/**
- * Implementation of listener_t.child_keys
- */
-static bool child_keys(private_ha_child_t *this, ike_sa_t *ike_sa,
- child_sa_t *child_sa, diffie_hellman_t *dh,
- chunk_t nonce_i, chunk_t nonce_r)
+METHOD(listener_t, child_keys, bool,
+ private_ha_child_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ bool initiator, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
{
ha_message_t *m;
chunk_t secret;
proposal_t *proposal;
u_int16_t alg, len;
- linked_list_t *list;
+ linked_list_t *local_ts, *remote_ts;
enumerator_t *enumerator;
traffic_selector_t *ts;
+ u_int seg_i, seg_o;
if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
{ /* do not sync SA between nodes */
@@ -61,6 +69,7 @@ static bool child_keys(private_ha_child_t *this, ike_sa_t *ike_sa,
m = ha_message_create(HA_CHILD_ADD);
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
+ m->add_attribute(m, HA_INITIATOR, (u_int8_t)initiator);
m->add_attribute(m, HA_INBOUND_SPI, child_sa->get_spi(child_sa, TRUE));
m->add_attribute(m, HA_OUTBOUND_SPI, child_sa->get_spi(child_sa, FALSE));
m->add_attribute(m, HA_INBOUND_CPI, child_sa->get_cpi(child_sa, TRUE));
@@ -90,31 +99,40 @@ static bool child_keys(private_ha_child_t *this, ike_sa_t *ike_sa,
chunk_clear(&secret);
}
- list = child_sa->get_traffic_selectors(child_sa, TRUE);
- enumerator = list->create_enumerator(list);
+ local_ts = child_sa->get_traffic_selectors(child_sa, TRUE);
+ enumerator = local_ts->create_enumerator(local_ts);
while (enumerator->enumerate(enumerator, &ts))
{
m->add_attribute(m, HA_LOCAL_TS, ts);
}
enumerator->destroy(enumerator);
- list = child_sa->get_traffic_selectors(child_sa, FALSE);
- enumerator = list->create_enumerator(list);
+ remote_ts = child_sa->get_traffic_selectors(child_sa, FALSE);
+ enumerator = remote_ts->create_enumerator(remote_ts);
while (enumerator->enumerate(enumerator, &ts))
{
m->add_attribute(m, HA_REMOTE_TS, ts);
}
enumerator->destroy(enumerator);
+ seg_i = this->kernel->get_segment_spi(this->kernel,
+ ike_sa->get_my_host(ike_sa), child_sa->get_spi(child_sa, TRUE));
+ seg_o = this->kernel->get_segment_spi(this->kernel,
+ ike_sa->get_other_host(ike_sa), child_sa->get_spi(child_sa, FALSE));
+ DBG1(DBG_CFG, "handling HA CHILD_SA %s{%d} %#R=== %#R "
+ "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
+ child_sa->get_reqid(child_sa), local_ts, remote_ts,
+ seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
+ seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
+
this->socket->push(this->socket, m);
+ m->destroy(m);
return TRUE;
}
-/**
- * Implementation of listener_t.child_state_change
- */
-static bool child_state_change(private_ha_child_t *this, ike_sa_t *ike_sa,
- child_sa_t *child_sa, child_sa_state_t state)
+METHOD(listener_t, child_state_change, bool,
+ private_ha_child_t *this, ike_sa_t *ike_sa,
+ child_sa_t *child_sa, child_sa_state_t state)
{
if (!ike_sa ||
ike_sa->get_state(ike_sa) == IKE_PASSIVE ||
@@ -138,14 +156,13 @@ static bool child_state_change(private_ha_child_t *this, ike_sa_t *ike_sa,
m->add_attribute(m, HA_INBOUND_SPI,
child_sa->get_spi(child_sa, TRUE));
this->socket->push(this->socket, m);
+ m->destroy(m);
}
return TRUE;
}
-/**
- * Implementation of ha_child_t.destroy.
- */
-static void destroy(private_ha_child_t *this)
+METHOD(ha_child_t, destroy, void,
+ private_ha_child_t *this)
{
free(this);
}
@@ -153,17 +170,24 @@ static void destroy(private_ha_child_t *this)
/**
* See header
*/
-ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel)
+ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
+ ha_segments_t *segments, ha_kernel_t *kernel)
{
- private_ha_child_t *this = malloc_thing(private_ha_child_t);
-
- memset(&this->public.listener, 0, sizeof(listener_t));
- this->public.listener.child_keys = (bool(*)(listener_t*, ike_sa_t *ike_sa, child_sa_t *child_sa, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r))child_keys;
- this->public.listener.child_state_change = (bool(*)(listener_t*,ike_sa_t *ike_sa, child_sa_t *child_sa, child_sa_state_t state))child_state_change;
- this->public.destroy = (void(*)(ha_child_t*))destroy;
-
- this->socket = socket;
- this->tunnel = tunnel;
+ private_ha_child_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .child_keys = _child_keys,
+ .child_state_change = _child_state_change,
+ },
+ .destroy = _destroy,
+ },
+ .socket = socket,
+ .tunnel = tunnel,
+ .segments = segments,
+ .kernel = kernel,
+ );
return &this->public;
}
diff --git a/src/libcharon/plugins/ha/ha_child.h b/src/libcharon/plugins/ha/ha_child.h
index ea83495f7..56cd769ba 100644
--- a/src/libcharon/plugins/ha/ha_child.h
+++ b/src/libcharon/plugins/ha/ha_child.h
@@ -21,14 +21,15 @@
#ifndef HA_CHILD_H_
#define HA_CHILD_H_
+typedef struct ha_child_t ha_child_t;
+
#include "ha_socket.h"
#include "ha_tunnel.h"
#include "ha_segments.h"
+#include "ha_kernel.h"
#include <daemon.h>
-typedef struct ha_child_t ha_child_t;
-
/**
* Listener to synchronize CHILD_SAs.
*/
@@ -50,8 +51,11 @@ struct ha_child_t {
*
* @param socket socket to use for sending synchronization messages
* @param tunnel tunnel securing sync messages, if any
+ * @param segments segment handling
+ * @param kernel kernel helper
* @return CHILD listener
*/
-ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel);
+ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
+ ha_segments_t *segments, ha_kernel_t *kernel);
-#endif /* HA_CHILD_ @}*/
+#endif /** HA_CHILD_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_ctl.c b/src/libcharon/plugins/ha/ha_ctl.c
index 441d26d9e..e188a8484 100644
--- a/src/libcharon/plugins/ha/ha_ctl.c
+++ b/src/libcharon/plugins/ha/ha_ctl.c
@@ -45,6 +45,11 @@ struct private_ha_ctl_t {
ha_segments_t *segments;
/**
+ * Resynchronization message cache
+ */
+ ha_cache_t *cache;
+
+ /**
* FIFO reader thread
*/
callback_job_t *job;
@@ -84,7 +89,7 @@ static job_requeue_t dispatch_fifo(private_ha_ctl_t *this)
this->segments->deactivate(this->segments, segment, TRUE);
break;
case '*':
- this->segments->resync(this->segments, segment);
+ this->cache->resync(this->cache, segment);
break;
default:
break;
@@ -96,10 +101,8 @@ static job_requeue_t dispatch_fifo(private_ha_ctl_t *this)
return JOB_REQUEUE_DIRECT;
}
-/**
- * Implementation of ha_ctl_t.destroy.
- */
-static void destroy(private_ha_ctl_t *this)
+METHOD(ha_ctl_t, destroy, void,
+ private_ha_ctl_t *this)
{
this->job->cancel(this->job);
free(this);
@@ -108,11 +111,17 @@ static void destroy(private_ha_ctl_t *this)
/**
* See header
*/
-ha_ctl_t *ha_ctl_create(ha_segments_t *segments)
+ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache)
{
- private_ha_ctl_t *this = malloc_thing(private_ha_ctl_t);
+ private_ha_ctl_t *this;
- this->public.destroy = (void(*)(ha_ctl_t*))destroy;
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ },
+ .segments = segments,
+ .cache = cache,
+ );
if (access(HA_FIFO, R_OK|W_OK) != 0)
{
@@ -123,7 +132,6 @@ ha_ctl_t *ha_ctl_create(ha_segments_t *segments)
}
}
- this->segments = segments;
this->job = callback_job_create((callback_job_cb_t)dispatch_fifo,
this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
diff --git a/src/libcharon/plugins/ha/ha_ctl.h b/src/libcharon/plugins/ha/ha_ctl.h
index f33a809be..1e717832a 100644
--- a/src/libcharon/plugins/ha/ha_ctl.h
+++ b/src/libcharon/plugins/ha/ha_ctl.h
@@ -22,6 +22,7 @@
#define HA_CTL_H_
#include "ha_segments.h"
+#include "ha_cache.h"
typedef struct ha_ctl_t ha_ctl_t;
@@ -40,8 +41,9 @@ struct ha_ctl_t {
* Create a ha_ctl instance.
*
* @param segments segments to control
+ * @param cache message cache for resynchronization
* @return HA control interface
*/
-ha_ctl_t *ha_ctl_create(ha_segments_t *segments);
+ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache);
-#endif /* HA_CTL_ @}*/
+#endif /** HA_CTL_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index 7df2f1fa8..3bc426ea0 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -41,6 +41,21 @@ struct private_ha_dispatcher_t {
ha_segments_t *segments;
/**
+ * Cache for resync
+ */
+ ha_cache_t *cache;
+
+ /**
+ * Kernel helper
+ */
+ ha_kernel_t *kernel;
+
+ /**
+ * HA enabled pool
+ */
+ ha_attribute_t *attr;
+
+ /**
* Dispatcher job
*/
callback_job_t *job;
@@ -153,6 +168,8 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
old_sa = NULL;
}
ike_sa->set_state(ike_sa, IKE_CONNECTING);
+ this->cache->cache(this->cache, ike_sa, message);
+ message = NULL;
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
else
@@ -167,6 +184,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
}
+ DESTROY_IF(message);
}
/**
@@ -201,6 +219,8 @@ static void process_ike_update(private_ha_dispatcher_t *this,
enumerator_t *enumerator;
ike_sa_t *ike_sa = NULL;
peer_cfg_t *peer_cfg = NULL;
+ auth_cfg_t *auth;
+ bool received_vip = FALSE;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -222,6 +242,11 @@ static void process_ike_update(private_ha_dispatcher_t *this,
case HA_REMOTE_ID:
ike_sa->set_other_id(ike_sa, value.id->clone(value.id));
break;
+ case HA_REMOTE_EAP_ID:
+ auth = auth_cfg_create();
+ auth->add(auth, AUTH_RULE_EAP_IDENTITY, value.id->clone(value.id));
+ ike_sa->add_auth_cfg(ike_sa, FALSE, auth);
+ break;
case HA_LOCAL_ADDR:
ike_sa->set_my_host(ike_sa, value.host->clone(value.host));
break;
@@ -233,6 +258,7 @@ static void process_ike_update(private_ha_dispatcher_t *this,
break;
case HA_REMOTE_VIP:
ike_sa->set_virtual_ip(ike_sa, FALSE, value.host);
+ received_vip = TRUE;
break;
case HA_ADDITIONAL_ADDR:
ike_sa->add_additional_address(ike_sa,
@@ -265,12 +291,6 @@ static void process_ike_update(private_ha_dispatcher_t *this,
set_condition(ike_sa, value.u32, COND_CERTREQ_SEEN);
set_condition(ike_sa, value.u32, COND_ORIGINAL_INITIATOR);
break;
- case HA_INITIATE_MID:
- ike_sa->set_message_id(ike_sa, TRUE, value.u32);
- break;
- case HA_RESPOND_MID:
- ike_sa->set_message_id(ike_sa, FALSE, value.u32);
- break;
default:
break;
}
@@ -282,10 +302,81 @@ static void process_ike_update(private_ha_dispatcher_t *this,
if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
ike_sa->get_peer_cfg(ike_sa))
{
+ DBG1(DBG_CFG, "installed HA passive IKE_SA '%s' %H[%Y]...%H[%Y]",
+ ike_sa->get_name(ike_sa),
+ ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
+ ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
ike_sa->set_state(ike_sa, IKE_PASSIVE);
}
+ if (received_vip)
+ {
+ host_t *vip;
+ char *pool;
+
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+ if (peer_cfg && vip)
+ {
+ pool = peer_cfg->get_pool(peer_cfg);
+ if (pool)
+ {
+ this->attr->reserve(this->attr, pool, vip);
+ }
+ }
+ }
+ this->cache->cache(this->cache, ike_sa, message);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
+ else
+ {
+ DBG1(DBG_CFG, "passive HA IKE_SA to update not found");
+ message->destroy(message);
+ }
+}
+
+/**
+ * Process messages of type IKE_MID_INITIATOR/RESPONDER
+ */
+static void process_ike_mid(private_ha_dispatcher_t *this,
+ ha_message_t *message, bool initiator)
+{
+ ha_message_attribute_t attribute;
+ ha_message_value_t value;
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa = NULL;
+ u_int32_t mid = 0;
+
+ enumerator = message->create_attribute_enumerator(message);
+ while (enumerator->enumerate(enumerator, &attribute, &value))
+ {
+ switch (attribute)
+ {
+ case HA_IKE_ID:
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+ value.ike_sa_id);
+ break;
+ case HA_MID:
+ mid = value.u32;
+ break;
+ default:
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (ike_sa)
+ {
+ if (mid)
+ {
+ ike_sa->set_message_id(ike_sa, initiator, mid);
+ }
+ this->cache->cache(this->cache, ike_sa, message);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ message->destroy(message);
+ }
}
/**
@@ -297,7 +388,7 @@ static void process_ike_delete(private_ha_dispatcher_t *this,
ha_message_attribute_t attribute;
ha_message_value_t value;
enumerator_t *enumerator;
- ike_sa_t *ike_sa;
+ ike_sa_t *ike_sa = NULL;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -307,17 +398,22 @@ static void process_ike_delete(private_ha_dispatcher_t *this,
case HA_IKE_ID:
ike_sa = charon->ike_sa_manager->checkout(
charon->ike_sa_manager, value.ike_sa_id);
- if (ike_sa)
- {
- charon->ike_sa_manager->checkin_and_destroy(
- charon->ike_sa_manager, ike_sa);
- }
break;
default:
break;
}
}
enumerator->destroy(enumerator);
+ if (ike_sa)
+ {
+ this->cache->cache(this->cache, ike_sa, message);
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ message->destroy(message);
+ }
}
/**
@@ -366,6 +462,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
u_int16_t inbound_cpi = 0, outbound_cpi = 0;
u_int8_t mode = MODE_TUNNEL, ipcomp = 0;
u_int16_t encr = ENCR_UNDEFINED, integ = AUTH_UNDEFINED, len = 0;
+ u_int seg_i, seg_o;
chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
chunk_t encr_i, integ_i, encr_r, integ_r;
linked_list_t *local_ts, *remote_ts;
@@ -381,11 +478,13 @@ static void process_child_add(private_ha_dispatcher_t *this,
case HA_IKE_ID:
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
value.ike_sa_id);
- initiator = value.ike_sa_id->is_initiator(value.ike_sa_id);
break;
case HA_CONFIG_NAME:
config_name = value.str;
break;
+ case HA_INITIATOR:
+ initiator = value.u8;
+ break;
case HA_INBOUND_SPI:
inbound_spi = value.u32;
break;
@@ -431,6 +530,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
if (!ike_sa)
{
DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
+ message->destroy(message);
return;
}
config = find_child_cfg(ike_sa, config_name);
@@ -438,6 +538,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
{
DBG1(DBG_CHD, "HA is missing nodes child configuration");
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ message->destroy(message);
return;
}
@@ -524,15 +625,27 @@ static void process_child_add(private_ha_dispatcher_t *this,
local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ message->destroy(message);
return;
}
+ seg_i = this->kernel->get_segment_spi(this->kernel,
+ ike_sa->get_my_host(ike_sa), inbound_spi);
+ seg_o = this->kernel->get_segment_spi(this->kernel,
+ ike_sa->get_other_host(ike_sa), outbound_spi);
+
+ DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R=== %#R "
+ "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
+ child_sa->get_reqid(child_sa), local_ts, remote_ts,
+ seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
+ seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
child_sa->add_policies(child_sa, local_ts, remote_ts);
local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
child_sa->set_state(child_sa, CHILD_INSTALLED);
ike_sa->add_child_sa(ike_sa, child_sa);
+ message->destroy(message);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
@@ -546,6 +659,8 @@ static void process_child_delete(private_ha_dispatcher_t *this,
ha_message_value_t value;
enumerator_t *enumerator;
ike_sa_t *ike_sa = NULL;
+ child_sa_t *child_sa;
+ u_int32_t spi = 0;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -557,20 +672,24 @@ static void process_child_delete(private_ha_dispatcher_t *this,
value.ike_sa_id);
break;
case HA_INBOUND_SPI:
- if (ike_sa)
- {
- ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, value.u32);
- }
+ spi = value.u32;
break;
default:
break;
}
}
+ enumerator->destroy(enumerator);
+
if (ike_sa)
{
+ child_sa = ike_sa->get_child_sa(ike_sa, PROTO_ESP, spi, TRUE);
+ if (child_sa)
+ {
+ ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, spi);
+ }
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
- enumerator->destroy(enumerator);
+ message->destroy(message);
}
/**
@@ -605,6 +724,7 @@ static void process_segment(private_ha_dispatcher_t *this,
}
}
enumerator->destroy(enumerator);
+ message->destroy(message);
}
/**
@@ -633,6 +753,7 @@ static void process_status(private_ha_dispatcher_t *this,
enumerator->destroy(enumerator);
this->segments->handle_status(this->segments, mask);
+ message->destroy(message);
}
/**
@@ -651,13 +772,14 @@ static void process_resync(private_ha_dispatcher_t *this,
switch (attribute)
{
case HA_SEGMENT:
- this->segments->resync(this->segments, value.u16);
+ this->cache->resync(this->cache, value.u16);
break;
default:
break;
}
}
enumerator->destroy(enumerator);
+ message->destroy(message);
}
/**
@@ -666,9 +788,16 @@ static void process_resync(private_ha_dispatcher_t *this,
static job_requeue_t dispatch(private_ha_dispatcher_t *this)
{
ha_message_t *message;
+ ha_message_type_t type;
message = this->socket->pull(this->socket);
- switch (message->get_type(message))
+ type = message->get_type(message);
+ if (type != HA_STATUS)
+ {
+ DBG2(DBG_CFG, "received HA %N message", ha_message_type_names,
+ message->get_type(message));
+ }
+ switch (type)
{
case HA_IKE_ADD:
process_ike_add(this, message);
@@ -676,6 +805,12 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this)
case HA_IKE_UPDATE:
process_ike_update(this, message);
break;
+ case HA_IKE_MID_INITIATOR:
+ process_ike_mid(this, message, TRUE);
+ break;
+ case HA_IKE_MID_RESPONDER:
+ process_ike_mid(this, message, FALSE);
+ break;
case HA_IKE_DELETE:
process_ike_delete(this, message);
break;
@@ -698,19 +833,15 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this)
process_resync(this, message);
break;
default:
- DBG1(DBG_CFG, "received unknown HA message type %d",
- message->get_type(message));
+ DBG1(DBG_CFG, "received unknown HA message type %d", type);
+ message->destroy(message);
break;
}
- message->destroy(message);
-
return JOB_REQUEUE_DIRECT;
}
-/**
- * Implementation of ha_dispatcher_t.destroy.
- */
-static void destroy(private_ha_dispatcher_t *this)
+METHOD(ha_dispatcher_t, destroy, void,
+ private_ha_dispatcher_t *this)
{
this->job->cancel(this->job);
free(this);
@@ -720,14 +851,22 @@ static void destroy(private_ha_dispatcher_t *this)
* See header
*/
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
- ha_segments_t *segments)
+ ha_segments_t *segments, ha_cache_t *cache,
+ ha_kernel_t *kernel, ha_attribute_t *attr)
{
- private_ha_dispatcher_t *this = malloc_thing(private_ha_dispatcher_t);
-
- this->public.destroy = (void(*)(ha_dispatcher_t*))destroy;
-
- this->socket = socket;
- this->segments = segments;
+ private_ha_dispatcher_t *this;
+
+
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ },
+ .socket = socket,
+ .segments = segments,
+ .cache = cache,
+ .kernel = kernel,
+ .attr = attr,
+ );
this->job = callback_job_create((callback_job_cb_t)dispatch,
this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.h b/src/libcharon/plugins/ha/ha_dispatcher.h
index d2baace3f..105a40473 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.h
+++ b/src/libcharon/plugins/ha/ha_dispatcher.h
@@ -23,6 +23,9 @@
#include "ha_socket.h"
#include "ha_segments.h"
+#include "ha_cache.h"
+#include "ha_kernel.h"
+#include "ha_attribute.h"
typedef struct ha_dispatcher_t ha_dispatcher_t;
@@ -42,9 +45,13 @@ struct ha_dispatcher_t {
*
* @param socket socket to pull messages from
* @param segments segments to control based on received messages
+ * @param cache message cache to use for resynchronization
+ * @param kernel kernel helper
+ * @param attr HA enabled pool
* @return dispatcher object
*/
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
- ha_segments_t *segments);
+ ha_segments_t *segments, ha_cache_t *cache,
+ ha_kernel_t *kernel, ha_attribute_t *attr);
-#endif /* HA_DISPATCHER_ @}*/
+#endif /** HA_DISPATCHER_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c
index 1f025d0e5..1efba4e8f 100644
--- a/src/libcharon/plugins/ha/ha_ike.c
+++ b/src/libcharon/plugins/ha/ha_ike.c
@@ -36,6 +36,11 @@ struct private_ha_ike_t {
* tunnel securing sync messages
*/
ha_tunnel_t *tunnel;
+
+ /**
+ * message cache
+ */
+ ha_cache_t *cache;
};
/**
@@ -62,12 +67,9 @@ static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext)
return 0;
}
-/**
- * Implementation of listener_t.ike_keys
- */
-static bool ike_keys(private_ha_ike_t *this, ike_sa_t *ike_sa,
- diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
- ike_sa_t *rekey)
+METHOD(listener_t, ike_keys, bool,
+ private_ha_ike_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
+ chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey)
{
ha_message_t *m;
chunk_t secret;
@@ -120,14 +122,13 @@ static bool ike_keys(private_ha_ike_t *this, ike_sa_t *ike_sa,
chunk_clear(&secret);
this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
return TRUE;
}
-/**
- * Implementation of listener_t.ike_updown
- */
-static bool ike_updown(private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
+METHOD(listener_t, ike_updown, bool,
+ private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
{
ha_message_t *m;
@@ -147,6 +148,7 @@ static bool ike_updown(private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
u_int32_t extension, condition;
host_t *addr;
ike_sa_id_t *id;
+ identification_t *eap_id;
peer_cfg = ike_sa->get_peer_cfg(ike_sa);
@@ -168,6 +170,11 @@ static bool ike_updown(private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
m->add_attribute(m, HA_IKE_ID, id);
m->add_attribute(m, HA_LOCAL_ID, ike_sa->get_my_id(ike_sa));
m->add_attribute(m, HA_REMOTE_ID, ike_sa->get_other_id(ike_sa));
+ eap_id = ike_sa->get_other_eap_id(ike_sa);
+ if (!eap_id->equals(eap_id, ike_sa->get_other_id(ike_sa)))
+ {
+ m->add_attribute(m, HA_REMOTE_EAP_ID, eap_id);
+ }
m->add_attribute(m, HA_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
m->add_attribute(m, HA_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
m->add_attribute(m, HA_CONDITIONS, condition);
@@ -186,24 +193,31 @@ static bool ike_updown(private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
}
this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
return TRUE;
}
-/**
- * Implementation of listener_t.ike_rekey
- */
-static bool ike_rekey(private_ha_ike_t *this, ike_sa_t *old, ike_sa_t *new)
+METHOD(listener_t, ike_rekey, bool,
+ private_ha_ike_t *this, ike_sa_t *old, ike_sa_t *new)
{
ike_updown(this, old, FALSE);
ike_updown(this, new, TRUE);
return TRUE;
}
-/**
- * Implementation of listener_t.message
- */
-static bool message_hook(private_ha_ike_t *this, ike_sa_t *ike_sa,
- message_t *message, bool incoming)
+METHOD(listener_t, ike_state_change, bool,
+ private_ha_ike_t *this, ike_sa_t *ike_sa, ike_sa_state_t new)
+{
+ /* delete any remaining cache entry if IKE_SA gets destroyed */
+ if (new == IKE_DESTROYING)
+ {
+ this->cache->delete(this->cache, ike_sa);
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, message_hook, bool,
+ private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming)
{
if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
{ /* do not sync SA between nodes */
@@ -214,20 +228,19 @@ static bool message_hook(private_ha_ike_t *this, ike_sa_t *ike_sa,
message->get_request(message))
{ /* we sync on requests, but skip it on IKE_SA_INIT */
ha_message_t *m;
- u_int32_t mid;
- m = ha_message_create(HA_IKE_UPDATE);
- m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
- mid = message->get_message_id(message) + 1;
if (incoming)
{
- m->add_attribute(m, HA_RESPOND_MID, mid);
+ m = ha_message_create(HA_IKE_MID_RESPONDER);
}
else
{
- m->add_attribute(m, HA_INITIATE_MID, mid);
+ m = ha_message_create(HA_IKE_MID_INITIATOR);
}
+ m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
+ m->add_attribute(m, HA_MID, message->get_message_id(message) + 1);
this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
}
if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
message->get_exchange_type(message) == IKE_AUTH &&
@@ -245,15 +258,14 @@ static bool message_hook(private_ha_ike_t *this, ike_sa_t *ike_sa,
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
m->add_attribute(m, HA_REMOTE_VIP, vip);
this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
}
}
return TRUE;
}
-/**
- * Implementation of ha_ike_t.destroy.
- */
-static void destroy(private_ha_ike_t *this)
+METHOD(ha_ike_t, destroy, void,
+ private_ha_ike_t *this)
{
free(this);
}
@@ -261,19 +273,26 @@ static void destroy(private_ha_ike_t *this)
/**
* See header
*/
-ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel)
+ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
+ ha_cache_t *cache)
{
- private_ha_ike_t *this = malloc_thing(private_ha_ike_t);
-
- memset(&this->public.listener, 0, sizeof(listener_t));
- this->public.listener.ike_keys = (bool(*)(listener_t*, ike_sa_t *ike_sa, diffie_hellman_t *dh,chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey))ike_keys;
- this->public.listener.ike_updown = (bool(*)(listener_t*,ike_sa_t *ike_sa, bool up))ike_updown;
- this->public.listener.ike_rekey = (bool(*)(listener_t*,ike_sa_t *old, ike_sa_t *new))ike_rekey;
- this->public.listener.message = (bool(*)(listener_t*, ike_sa_t *, message_t *,bool))message_hook;
- this->public.destroy = (void(*)(ha_ike_t*))destroy;
-
- this->socket = socket;
- this->tunnel = tunnel;
+ private_ha_ike_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .ike_keys = _ike_keys,
+ .ike_updown = _ike_updown,
+ .ike_rekey = _ike_rekey,
+ .ike_state_change = _ike_state_change,
+ .message = _message_hook,
+ },
+ .destroy = _destroy,
+ },
+ .socket = socket,
+ .tunnel = tunnel,
+ .cache = cache,
+ );
return &this->public;
}
diff --git a/src/libcharon/plugins/ha/ha_ike.h b/src/libcharon/plugins/ha/ha_ike.h
index 9de210e67..b22cd6250 100644
--- a/src/libcharon/plugins/ha/ha_ike.h
+++ b/src/libcharon/plugins/ha/ha_ike.h
@@ -21,14 +21,15 @@
#ifndef HA_IKE_H_
#define HA_IKE_H_
+typedef struct ha_ike_t ha_ike_t;
+
#include "ha_socket.h"
#include "ha_tunnel.h"
#include "ha_segments.h"
+#include "ha_cache.h"
#include <daemon.h>
-typedef struct ha_ike_t ha_ike_t;
-
/**
* Listener to synchronize IKE_SAs.
*/
@@ -50,8 +51,10 @@ struct ha_ike_t {
*
* @param socket socket to use for sending synchronization messages
* @param tunnel tunnel securing sync messages, if any
+ * @param cache message cache
* @return IKE listener
*/
-ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel);
+ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
+ ha_cache_t *cache);
-#endif /* HA_IKE_ @}*/
+#endif /** HA_IKE_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_kernel.c b/src/libcharon/plugins/ha/ha_kernel.c
index 0ad9c22c3..10a63453a 100644
--- a/src/libcharon/plugins/ha/ha_kernel.c
+++ b/src/libcharon/plugins/ha/ha_kernel.c
@@ -52,24 +52,57 @@ struct private_ha_kernel_t {
};
/**
- * Implementation of ha_kernel_t.in_segment
+ * Segmentate a calculated hash
*/
-static bool in_segment(private_ha_kernel_t *this, host_t *host, u_int segment)
+static u_int hash2segment(private_ha_kernel_t *this, u_int64_t hash)
+{
+ return ((hash * this->count) >> 32) + 1;
+}
+
+/**
+ * Get a host as an integer for hashing
+ */
+static u_int32_t host2int(host_t *host)
{
if (host->get_family(host) == AF_INET)
{
- unsigned long hash;
- u_int32_t addr;
+ return *(u_int32_t*)host->get_address(host).ptr;
+ }
+ return 0;
+}
- addr = *(u_int32_t*)host->get_address(host).ptr;
- hash = jhash_1word(ntohl(addr), this->initval);
+METHOD(ha_kernel_t, get_segment, u_int,
+ private_ha_kernel_t *this, host_t *host)
+{
+ unsigned long hash;
+ u_int32_t addr;
- if ((((u_int64_t)hash * this->count) >> 32) + 1 == segment)
- {
- return TRUE;
- }
- }
- return FALSE;
+ addr = host2int(host);
+ hash = jhash_1word(ntohl(addr), this->initval);
+
+ return hash2segment(this, hash);
+}
+
+METHOD(ha_kernel_t, get_segment_spi, u_int,
+ private_ha_kernel_t *this, host_t *host, u_int32_t spi)
+{
+ unsigned long hash;
+ u_int32_t addr;
+
+ addr = host2int(host);
+ hash = jhash_2words(ntohl(addr), ntohl(spi), this->initval);
+
+ return hash2segment(this, hash);
+}
+
+METHOD(ha_kernel_t, get_segment_int, u_int,
+ private_ha_kernel_t *this, int n)
+{
+ unsigned long hash;
+
+ hash = jhash_1word(ntohl(n), this->initval);
+
+ return hash2segment(this, hash);
}
/**
@@ -142,10 +175,8 @@ static segment_mask_t get_active(private_ha_kernel_t *this, char *file)
return mask;
}
-/**
- * Implementation of ha_kernel_t.activate
- */
-static void activate(private_ha_kernel_t *this, u_int segment)
+METHOD(ha_kernel_t, activate, void,
+ private_ha_kernel_t *this, u_int segment)
{
enumerator_t *enumerator;
char *file;
@@ -158,10 +189,8 @@ static void activate(private_ha_kernel_t *this, u_int segment)
enumerator->destroy(enumerator);
}
-/**
- * Implementation of ha_kernel_t.deactivate
- */
-static void deactivate(private_ha_kernel_t *this, u_int segment)
+METHOD(ha_kernel_t, deactivate, void,
+ private_ha_kernel_t *this, u_int segment)
{
enumerator_t *enumerator;
char *file;
@@ -199,10 +228,8 @@ static void disable_all(private_ha_kernel_t *this)
enumerator->destroy(enumerator);
}
-/**
- * Implementation of ha_kernel_t.destroy.
- */
-static void destroy(private_ha_kernel_t *this)
+METHOD(ha_kernel_t, destroy, void,
+ private_ha_kernel_t *this)
{
free(this);
}
@@ -212,15 +239,20 @@ static void destroy(private_ha_kernel_t *this)
*/
ha_kernel_t *ha_kernel_create(u_int count)
{
- private_ha_kernel_t *this = malloc_thing(private_ha_kernel_t);
-
- this->public.in_segment = (bool(*)(ha_kernel_t*, host_t *host, u_int segment))in_segment;
- this->public.activate = (void(*)(ha_kernel_t*, u_int segment))activate;
- this->public.deactivate = (void(*)(ha_kernel_t*, u_int segment))deactivate;
- this->public.destroy = (void(*)(ha_kernel_t*))destroy;
+ private_ha_kernel_t *this;
- this->initval = 0;
- this->count = count;
+ INIT(this,
+ .public = {
+ .get_segment = _get_segment,
+ .get_segment_spi = _get_segment_spi,
+ .get_segment_int = _get_segment_int,
+ .activate = _activate,
+ .deactivate = _deactivate,
+ .destroy = _destroy,
+ },
+ .initval = 0,
+ .count = count,
+ );
disable_all(this);
diff --git a/src/libcharon/plugins/ha/ha_kernel.h b/src/libcharon/plugins/ha/ha_kernel.h
index b37cc7667..7b56f1e3a 100644
--- a/src/libcharon/plugins/ha/ha_kernel.h
+++ b/src/libcharon/plugins/ha/ha_kernel.h
@@ -31,13 +31,28 @@ typedef struct ha_kernel_t ha_kernel_t;
struct ha_kernel_t {
/**
- * Check if a host is in a segment.
+ * Get the segment a host is in.
*
- * @param host host to check
- * @param segment segment
- * @return TRUE if host belongs to segment
+ * @param host host to get segment for
+ * @return segment number
*/
- bool (*in_segment)(ha_kernel_t *this, host_t *host, u_int segment);
+ u_int (*get_segment)(ha_kernel_t *this, host_t *host);
+
+ /**
+ * Get the segment a host/SPI is in, as used for CHILD_SA segmentation.
+ *
+ * @param host host to get segment for
+ * @param spi SPI to include in hash
+ * @return segment number
+ */
+ u_int (*get_segment_spi)(ha_kernel_t *this, host_t *host, u_int32_t spi);
+
+ /**
+ * Get the segment an arbitrary integer is in.
+ *
+ * @param n integer to segmentate
+ */
+ u_int (*get_segment_int)(ha_kernel_t *this, int n);
/**
* Activate a segment at kernel level for all cluster addresses.
@@ -63,8 +78,7 @@ struct ha_kernel_t {
* Create a ha_kernel instance.
*
* @param count total number of segments to use
- * @param active bitmask of initially active segments
*/
ha_kernel_t *ha_kernel_create(u_int count);
-#endif /* HA_KERNEL_ @}*/
+#endif /** HA_KERNEL_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c
index 54b10f05d..7ce9cbe09 100644
--- a/src/libcharon/plugins/ha/ha_message.c
+++ b/src/libcharon/plugins/ha/ha_message.c
@@ -46,6 +46,20 @@ struct private_ha_message_t {
chunk_t buf;
};
+ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC,
+ "IKE_ADD",
+ "IKE_UPDATE",
+ "IKE_MID_INITIATOR",
+ "IKE_MID_RESPONDER",
+ "IKE_DELETE",
+ "CHILD_ADD",
+ "CHILD_DELETE",
+ "SEGMENT_DROP",
+ "SEGMENT_TAKE",
+ "STATUS",
+ "RESYNC",
+);
+
typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t;
/**
@@ -93,10 +107,8 @@ struct ts_encoding_t {
char encoding[];
} __attribute__((packed));
-/**
- * Implementation of ha_message_t.get_type
- */
-static ha_message_type_t get_type(private_ha_message_t *this)
+METHOD(ha_message_t, get_type, ha_message_type_t,
+ private_ha_message_t *this)
{
return this->buf.ptr[1];
}
@@ -119,11 +131,8 @@ static void check_buf(private_ha_message_t *this, size_t len)
}
}
-/**
- * Implementation of ha_message_t.add_attribute
- */
-static void add_attribute(private_ha_message_t *this,
- ha_message_attribute_t attribute, ...)
+METHOD(ha_message_t, add_attribute, void,
+ private_ha_message_t *this, ha_message_attribute_t attribute, ...)
{
size_t len;
va_list args;
@@ -154,6 +163,7 @@ static void add_attribute(private_ha_message_t *this,
/* identification_t* */
case HA_LOCAL_ID:
case HA_REMOTE_ID:
+ case HA_REMOTE_EAP_ID:
{
identification_encoding_t *enc;
identification_t *id;
@@ -203,6 +213,7 @@ static void add_attribute(private_ha_message_t *this,
break;
}
/* u_int8_t */
+ case HA_INITIATOR:
case HA_IPSEC_MODE:
case HA_IPCOMP:
{
@@ -237,8 +248,7 @@ static void add_attribute(private_ha_message_t *this,
case HA_EXTENSIONS:
case HA_INBOUND_SPI:
case HA_OUTBOUND_SPI:
- case HA_INITIATE_MID:
- case HA_RESPOND_MID:
+ case HA_MID:
{
u_int32_t val;
@@ -310,12 +320,9 @@ typedef struct {
void *cleanup_data;
} attribute_enumerator_t;
-/**
- * Implementation of create_attribute_enumerator().enumerate
- */
-static bool attribute_enumerate(attribute_enumerator_t *this,
- ha_message_attribute_t *attr_out,
- ha_message_value_t *value)
+METHOD(enumerator_t, attribute_enumerate, bool,
+ attribute_enumerator_t *this, ha_message_attribute_t *attr_out,
+ ha_message_value_t *value)
{
ha_message_attribute_t attr;
@@ -354,6 +361,7 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
/* identification_t* */
case HA_LOCAL_ID:
case HA_REMOTE_ID:
+ case HA_REMOTE_EAP_ID:
{
identification_encoding_t *enc;
@@ -417,6 +425,7 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
return TRUE;
}
/* u_int8_t */
+ case HA_INITIATOR:
case HA_IPSEC_MODE:
case HA_IPCOMP:
{
@@ -453,8 +462,7 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
case HA_EXTENSIONS:
case HA_INBOUND_SPI:
case HA_OUTBOUND_SPI:
- case HA_INITIATE_MID:
- case HA_RESPOND_MID:
+ case HA_MID:
{
if (this->buf.len < sizeof(u_int32_t))
{
@@ -559,10 +567,8 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
}
}
-/**
- * Implementation of create_attribute_enumerator().destroy
- */
-static void enum_destroy(attribute_enumerator_t *this)
+METHOD(enumerator_t, enum_destroy, void,
+ attribute_enumerator_t *this)
{
if (this->cleanup)
{
@@ -571,35 +577,30 @@ static void enum_destroy(attribute_enumerator_t *this)
free(this);
}
-/**
- * Implementation of ha_message_t.create_attribute_enumerator
- */
-static enumerator_t* create_attribute_enumerator(private_ha_message_t *this)
+METHOD(ha_message_t, create_attribute_enumerator, enumerator_t*,
+ private_ha_message_t *this)
{
- attribute_enumerator_t *e = malloc_thing(attribute_enumerator_t);
-
- e->public.enumerate = (void*)attribute_enumerate;
- e->public.destroy = (void*)enum_destroy;
+ attribute_enumerator_t *e;
- e->buf = chunk_skip(this->buf, 2);
- e->cleanup = NULL;
- e->cleanup_data = NULL;
+ INIT(e,
+ .public = {
+ .enumerate = (void*)_attribute_enumerate,
+ .destroy = _enum_destroy,
+ },
+ .buf = chunk_skip(this->buf, 2),
+ );
return &e->public;
}
-/**
- * Implementation of ha_message_t.get_encoding
- */
-static chunk_t get_encoding(private_ha_message_t *this)
+METHOD(ha_message_t, get_encoding, chunk_t,
+ private_ha_message_t *this)
{
return this->buf;
}
-/**
- * Implementation of ha_message_t.destroy.
- */
-static void destroy(private_ha_message_t *this)
+METHOD(ha_message_t, destroy, void,
+ private_ha_message_t *this)
{
free(this->buf.ptr);
free(this);
@@ -608,14 +609,17 @@ static void destroy(private_ha_message_t *this)
static private_ha_message_t *ha_message_create_generic()
{
- private_ha_message_t *this = malloc_thing(private_ha_message_t);
-
- this->public.get_type = (ha_message_type_t(*)(ha_message_t*))get_type;
- this->public.add_attribute = (void(*)(ha_message_t*, ha_message_attribute_t attribute, ...))add_attribute;
- this->public.create_attribute_enumerator = (enumerator_t*(*)(ha_message_t*))create_attribute_enumerator;
- this->public.get_encoding = (chunk_t(*)(ha_message_t*))get_encoding;
- this->public.destroy = (void(*)(ha_message_t*))destroy;
+ private_ha_message_t *this;
+ INIT(this,
+ .public = {
+ .get_type = _get_type,
+ .add_attribute = _add_attribute,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ .get_encoding = _get_encoding,
+ .destroy = _destroy,
+ },
+ );
return this;
}
diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h
index b2bc23724..50e11830f 100644
--- a/src/libcharon/plugins/ha/ha_message.h
+++ b/src/libcharon/plugins/ha/ha_message.h
@@ -30,7 +30,7 @@
/**
* Protocol version of this implementation
*/
-#define HA_MESSAGE_VERSION 1
+#define HA_MESSAGE_VERSION 2
typedef struct ha_message_t ha_message_t;
typedef enum ha_message_type_t ha_message_type_t;
@@ -43,8 +43,12 @@ typedef union ha_message_value_t ha_message_value_t;
enum ha_message_type_t {
/** add a completely new IKE_SA */
HA_IKE_ADD = 1,
- /** update an existing IKE_SA (message IDs, address update, ...) */
+ /** update an existing IKE_SA (identities, address update, ...) */
HA_IKE_UPDATE,
+ /** update initiator message id */
+ HA_IKE_MID_INITIATOR,
+ /** update responder message id */
+ HA_IKE_MID_RESPONDER,
/** delete an existing IKE_SA */
HA_IKE_DELETE,
/** add a new CHILD_SA */
@@ -62,6 +66,11 @@ enum ha_message_type_t {
};
/**
+ * Enum names for message types
+ */
+extern enum_name_t *ha_message_type_names;
+
+/**
* Type of attributes contained in a message
*/
enum ha_message_attribute_t {
@@ -73,6 +82,8 @@ enum ha_message_attribute_t {
HA_LOCAL_ID,
/** identification_t*, remote identity */
HA_REMOTE_ID,
+ /** identification_t*, remote EAP identity */
+ HA_REMOTE_EAP_ID,
/** host_t*, local address */
HA_LOCAL_ADDR,
/** host_t*, remote address */
@@ -89,6 +100,8 @@ enum ha_message_attribute_t {
HA_REMOTE_VIP,
/** host_t*, additional MOBIKE peer address */
HA_ADDITIONAL_ADDR,
+ /** u_int8_t, initiator of an exchange, TRUE for local */
+ HA_INITIATOR,
/** chunk_t, initiators nonce */
HA_NONCE_I,
/** chunk_t, responders nonce */
@@ -123,10 +136,8 @@ enum ha_message_attribute_t {
HA_LOCAL_TS,
/** traffic_selector_t*, remote traffic selector */
HA_REMOTE_TS,
- /** u_int32_t, initiating message ID */
- HA_INITIATE_MID,
- /** u_int32_t, responding message ID */
- HA_RESPOND_MID,
+ /** u_int32_t, message ID */
+ HA_MID,
/** u_int16_t, HA segment */
HA_SEGMENT,
};
@@ -190,7 +201,6 @@ struct ha_message_t {
/**
* Create a new ha_message instance, ready for adding attributes
*
- * @param version protocol version to create a message from
* @param type type of the message
*/
ha_message_t *ha_message_create(ha_message_type_t type);
@@ -202,4 +212,4 @@ ha_message_t *ha_message_create(ha_message_type_t type);
*/
ha_message_t *ha_message_parse(chunk_t data);
-#endif /* HA_MESSAGE_ @}*/
+#endif /** HA_MESSAGE_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_plugin.c b/src/libcharon/plugins/ha/ha_plugin.c
index ea255c8ab..e722b4f3a 100644
--- a/src/libcharon/plugins/ha/ha_plugin.c
+++ b/src/libcharon/plugins/ha/ha_plugin.c
@@ -21,8 +21,11 @@
#include "ha_dispatcher.h"
#include "ha_segments.h"
#include "ha_ctl.h"
+#include "ha_cache.h"
+#include "ha_attribute.h"
#include <daemon.h>
+#include <hydra.h>
#include <config/child_cfg.h>
typedef struct private_ha_plugin_t private_ha_plugin_t;
@@ -76,20 +79,31 @@ struct private_ha_plugin_t {
* Segment control interface via FIFO
*/
ha_ctl_t *ctl;
+
+ /**
+ * Message cache for resynchronization
+ */
+ ha_cache_t *cache;
+
+ /**
+ * Attribute provider
+ */
+ ha_attribute_t *attr;
};
-/**
- * Implementation of plugin_t.destroy
- */
-static void destroy(private_ha_plugin_t *this)
+METHOD(plugin_t, destroy, void,
+ private_ha_plugin_t *this)
{
DESTROY_IF(this->ctl);
+ hydra->attributes->remove_provider(hydra->attributes, &this->attr->provider);
charon->bus->remove_listener(charon->bus, &this->segments->listener);
charon->bus->remove_listener(charon->bus, &this->ike->listener);
charon->bus->remove_listener(charon->bus, &this->child->listener);
this->ike->destroy(this->ike);
this->child->destroy(this->child);
this->dispatcher->destroy(this->dispatcher);
+ this->attr->destroy(this->attr);
+ this->cache->destroy(this->cache);
this->segments->destroy(this->segments);
this->kernel->destroy(this->kernel);
this->socket->destroy(this->socket);
@@ -127,11 +141,9 @@ plugin_t *ha_plugin_create()
return NULL;
}
- this = malloc_thing(private_ha_plugin_t);
-
- this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
- this->tunnel = NULL;
- this->ctl = NULL;
+ INIT(this,
+ .public.plugin.destroy = _destroy,
+ );
if (secret)
{
@@ -146,17 +158,22 @@ plugin_t *ha_plugin_create()
}
this->kernel = ha_kernel_create(count);
this->segments = ha_segments_create(this->socket, this->kernel, this->tunnel,
- count, strcmp(local, remote) > 0, monitor, resync);
+ count, strcmp(local, remote) > 0, monitor);
+ this->cache = ha_cache_create(this->kernel, this->socket, resync, count);
if (fifo)
{
- this->ctl = ha_ctl_create(this->segments);
+ this->ctl = ha_ctl_create(this->segments, this->cache);
}
- this->dispatcher = ha_dispatcher_create(this->socket, this->segments);
- this->ike = ha_ike_create(this->socket, this->tunnel);
- this->child = ha_child_create(this->socket, this->tunnel);
+ this->attr = ha_attribute_create(this->kernel, this->segments);
+ this->dispatcher = ha_dispatcher_create(this->socket, this->segments,
+ this->cache, this->kernel, this->attr);
+ this->ike = ha_ike_create(this->socket, this->tunnel, this->cache);
+ this->child = ha_child_create(this->socket, this->tunnel, this->segments,
+ this->kernel);
charon->bus->add_listener(charon->bus, &this->segments->listener);
charon->bus->add_listener(charon->bus, &this->ike->listener);
charon->bus->add_listener(charon->bus, &this->child->listener);
+ hydra->attributes->add_provider(hydra->attributes, &this->attr->provider);
return &this->public.plugin;
}
diff --git a/src/libcharon/plugins/ha/ha_plugin.h b/src/libcharon/plugins/ha/ha_plugin.h
index 1ae2fe6dd..d4d746f91 100644
--- a/src/libcharon/plugins/ha/ha_plugin.h
+++ b/src/libcharon/plugins/ha/ha_plugin.h
@@ -44,4 +44,4 @@ struct ha_plugin_t {
plugin_t plugin;
};
-#endif /* HA_PLUGIN_H_ @}*/
+#endif /** HA_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_segments.c b/src/libcharon/plugins/ha/ha_segments.c
index 2199671fc..be2d7e428 100644
--- a/src/libcharon/plugins/ha/ha_segments.c
+++ b/src/libcharon/plugins/ha/ha_segments.c
@@ -22,8 +22,8 @@
#include <utils/linked_list.h>
#include <processing/jobs/callback_job.h>
-#define HEARTBEAT_DELAY 1000
-#define HEARTBEAT_TIMEOUT 2100
+#define DEFAULT_HEARTBEAT_DELAY 1000
+#define DEFAULT_HEARTBEAT_TIMEOUT 2100
typedef struct private_ha_segments_t private_ha_segments_t;
@@ -81,6 +81,16 @@ struct private_ha_segments_t {
* Node number
*/
u_int node;
+
+ /**
+ * Interval we send hearbeats
+ */
+ int heartbeat_delay;
+
+ /**
+ * Timeout for heartbeats received from other node
+ */
+ int heartbeat_timeout;
};
/**
@@ -168,8 +178,8 @@ static void enable_disable(private_ha_segments_t *this, u_int segment,
{
continue;
}
- if (this->kernel->in_segment(this->kernel,
- ike_sa->get_other_host(ike_sa), segment))
+ if (this->kernel->get_segment(this->kernel,
+ ike_sa->get_other_host(ike_sa)) == segment)
{
ike_sa->set_state(ike_sa, new);
}
@@ -183,6 +193,7 @@ static void enable_disable(private_ha_segments_t *this, u_int segment,
message = ha_message_create(type);
message->add_attribute(message, HA_SEGMENT, segment);
this->socket->push(this->socket, message);
+ message->destroy(message);
}
}
@@ -209,135 +220,37 @@ static void enable_disable_all(private_ha_segments_t *this, u_int segment,
this->mutex->unlock(this->mutex);
}
-/**
- * Implementation of ha_segments_t.activate
- */
-static void activate(private_ha_segments_t *this, u_int segment, bool notify)
+METHOD(ha_segments_t, activate, void,
+ private_ha_segments_t *this, u_int segment, bool notify)
{
enable_disable_all(this, segment, TRUE, notify);
}
-/**
- * Implementation of ha_segments_t.deactivate
- */
-static void deactivate(private_ha_segments_t *this, u_int segment, bool notify)
+METHOD(ha_segments_t, deactivate, void,
+ private_ha_segments_t *this, u_int segment, bool notify)
{
enable_disable_all(this, segment, FALSE, notify);
}
-/**
- * Rekey all children of an IKE_SA
- */
-static status_t rekey_children(ike_sa_t *ike_sa)
+METHOD(listener_t, alert_hook, bool,
+ private_ha_segments_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
{
- iterator_t *iterator;
- child_sa_t *child_sa;
- status_t status = SUCCESS;
-
- iterator = ike_sa->create_child_sa_iterator(ike_sa);
- while (iterator->iterate(iterator, (void**)&child_sa))
- {
- DBG1(DBG_CFG, "resyncing CHILD_SA");
- status = ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE));
- if (status == DESTROY_ME)
- {
- break;
- }
- }
- iterator->destroy(iterator);
- return status;
-}
-
-/**
- * Implementation of ha_segments_t.resync
- */
-static void resync(private_ha_segments_t *this, u_int segment)
-{
- ike_sa_t *ike_sa;
- enumerator_t *enumerator;
- linked_list_t *list;
- ike_sa_id_t *id;
-
- list = linked_list_create();
- this->mutex->lock(this->mutex);
-
- if (segment > 0 && segment <= this->count)
+ if (alert == ALERT_SHUTDOWN_SIGNAL)
{
- DBG1(DBG_CFG, "resyncing HA segment %d", segment);
-
- /* we do the actual rekeying in a seperate loop to avoid rekeying
- * an SA twice. */
- enumerator = charon->ike_sa_manager->create_enumerator(
- charon->ike_sa_manager);
- while (enumerator->enumerate(enumerator, &ike_sa))
+ if (this->job)
{
- if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
- this->kernel->in_segment(this->kernel,
- ike_sa->get_other_host(ike_sa), segment))
- {
- id = ike_sa->get_id(ike_sa);
- list->insert_last(list, id->clone(id));
- }
+ DBG1(DBG_CFG, "HA heartbeat active, dropping all segments");
+ deactivate(this, 0, TRUE);
}
- enumerator->destroy(enumerator);
- }
- this->mutex->unlock(this->mutex);
-
- while (list->remove_last(list, (void**)&id) == SUCCESS)
- {
- ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
- id->destroy(id);
- if (ike_sa)
+ else
{
- DBG1(DBG_CFG, "resyncing IKE_SA");
- if (ike_sa->rekey(ike_sa) != DESTROY_ME)
- {
- if (rekey_children(ike_sa) != DESTROY_ME)
- {
- charon->ike_sa_manager->checkin(
- charon->ike_sa_manager, ike_sa);
- continue;
- }
- }
- charon->ike_sa_manager->checkin_and_destroy(
- charon->ike_sa_manager, ike_sa);
+ DBG1(DBG_CFG, "no HA heartbeat active, closing IKE_SAs");
}
}
- list->destroy(list);
-}
-
-/**
- * Implementation of listener_t.alert
- */
-static bool alert_hook(private_ha_segments_t *this, ike_sa_t *ike_sa,
- alert_t alert, va_list args)
-{
- if (alert == ALERT_SHUTDOWN_SIGNAL)
- {
- deactivate(this, 0, TRUE);
- }
return TRUE;
}
/**
- * Request a resync of all segments
- */
-static job_requeue_t request_resync(private_ha_segments_t *this)
-{
- ha_message_t *message;
- int i;
-
- message = ha_message_create(HA_RESYNC);
- for (i = 1; i <= this->count; i++)
- {
- message->add_attribute(message, HA_SEGMENT, i);
- }
- this->socket->push(this->socket, message);
- return JOB_REQUEUE_NONE;
-}
-
-/**
* Monitor heartbeat activity of remote node
*/
static job_requeue_t watchdog(private_ha_segments_t *this)
@@ -349,7 +262,7 @@ static job_requeue_t watchdog(private_ha_segments_t *this)
pthread_cleanup_push((void*)this->mutex->unlock, this->mutex);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
timeout = this->condvar->timed_wait(this->condvar, this->mutex,
- HEARTBEAT_TIMEOUT);
+ this->heartbeat_timeout);
pthread_setcancelstate(oldstate, NULL);
pthread_cleanup_pop(TRUE);
if (timeout)
@@ -373,10 +286,8 @@ static void start_watchdog(private_ha_segments_t *this)
charon->processor->queue_job(charon->processor, (job_t*)this->job);
}
-/**
- * Implementation of ha_segments_t.handle_status
- */
-static void handle_status(private_ha_segments_t *this, segment_mask_t mask)
+METHOD(ha_segments_t, handle_status, void,
+ private_ha_segments_t *this, segment_mask_t mask)
{
segment_mask_t missing;
int i;
@@ -431,20 +342,25 @@ static job_requeue_t send_status(private_ha_segments_t *this)
}
this->socket->push(this->socket, message);
+ message->destroy(message);
/* schedule next invocation */
charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*)
callback_job_create((callback_job_cb_t)
send_status, this, NULL, NULL),
- HEARTBEAT_DELAY);
+ this->heartbeat_delay);
return JOB_REQUEUE_NONE;
}
-/**
- * Implementation of ha_segments_t.destroy.
- */
-static void destroy(private_ha_segments_t *this)
+METHOD(ha_segments_t, is_active, bool,
+ private_ha_segments_t *this, u_int segment)
+{
+ return (this->active & SEGMENTS_BIT(segment)) != 0;
+}
+
+METHOD(ha_segments_t, destroy, void,
+ private_ha_segments_t *this)
{
if (this->job)
{
@@ -460,44 +376,40 @@ static void destroy(private_ha_segments_t *this)
*/
ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
ha_tunnel_t *tunnel, u_int count, u_int node,
- bool monitor, bool sync)
+ bool monitor)
{
- private_ha_segments_t *this = malloc_thing(private_ha_segments_t);
-
- memset(&this->public.listener, 0, sizeof(listener_t));
- this->public.listener.alert = (bool(*)(listener_t*, ike_sa_t *, alert_t, va_list))alert_hook;
- this->public.activate = (void(*)(ha_segments_t*, u_int segment,bool))activate;
- this->public.deactivate = (void(*)(ha_segments_t*, u_int segment,bool))deactivate;
- this->public.resync = (void(*)(ha_segments_t*, u_int segment))resync;
- this->public.handle_status = (void(*)(ha_segments_t*, segment_mask_t mask))handle_status;
- this->public.destroy = (void(*)(ha_segments_t*))destroy;
-
- this->socket = socket;
- this->tunnel = tunnel;
- this->kernel = kernel;
- this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
- this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
- this->count = count;
- this->node = node;
- this->job = NULL;
-
- /* initially all segments are deactivated */
- this->active = 0;
+ private_ha_segments_t *this;
+
+ INIT(this,
+ .public = {
+ .listener.alert = _alert_hook,
+ .activate = _activate,
+ .deactivate = _deactivate,
+ .handle_status = _handle_status,
+ .is_active = _is_active,
+ .destroy = _destroy,
+ },
+ .socket = socket,
+ .tunnel = tunnel,
+ .kernel = kernel,
+ .count = count,
+ .node = node,
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .heartbeat_delay = lib->settings->get_int(lib->settings,
+ "charon.plugins.ha.heartbeat_delay", DEFAULT_HEARTBEAT_DELAY),
+ .heartbeat_timeout = lib->settings->get_int(lib->settings,
+ "charon.plugins.ha.heartbeat_timeout", DEFAULT_HEARTBEAT_TIMEOUT),
+ );
if (monitor)
{
+ DBG1(DBG_CFG, "starting HA heartbeat, delay %dms, timeout %dms",
+ this->heartbeat_delay, this->heartbeat_timeout);
send_status(this);
start_watchdog(this);
}
- if (sync)
- {
- /* request a resync as soon as we are up */
- charon->processor->queue_job(charon->processor, (job_t*)
- callback_job_create((callback_job_cb_t)request_resync,
- this, NULL, NULL));
- }
-
return &this->public;
}
diff --git a/src/libcharon/plugins/ha/ha_segments.h b/src/libcharon/plugins/ha/ha_segments.h
index 6d1cd5441..eb9e5c1d5 100644
--- a/src/libcharon/plugins/ha/ha_segments.h
+++ b/src/libcharon/plugins/ha/ha_segments.h
@@ -68,23 +68,19 @@ struct ha_segments_t {
void (*deactivate)(ha_segments_t *this, u_int segment, bool notify);
/**
- * Resync an active segment.
- *
- * To reintegrade a node into the cluster, resynchronization is reqired.
- * IKE_SAs and CHILD_SAs are synced automatically during rekeying. A call
- * to this method enforces a rekeying immediately sync all state of a
- * segment.
+ * Handle a status message from the remote node.
*
- * @param segment segment to resync
+ * @param mask segments the remote node is serving actively
*/
- void (*resync)(ha_segments_t *this, u_int segment);
+ void (*handle_status)(ha_segments_t *this, segment_mask_t mask);
/**
- * Handle a status message from the remote node.
+ * Check if a given segment is currently active.
*
- * @param mask segments the remote node is serving actively
+ * @param segment segment to check
+ * @return TRUE if segment active
*/
- void (*handle_status)(ha_segments_t *this, segment_mask_t mask);
+ bool (*is_active)(ha_segments_t *this, u_int segment);
/**
* Destroy a ha_segments_t.
@@ -101,11 +97,10 @@ struct ha_segments_t {
* @param count number of segments the cluster uses
* @param node node, currently 1 or 0
* @param monitor should we use monitoring functionality
- * @param resync request a complete resync on startup
* @return segment object
*/
ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
ha_tunnel_t *tunnel, u_int count, u_int node,
- bool monitor, bool resync);
+ bool monitor);
-#endif /* HA_SEGMENTS_ @}*/
+#endif /** HA_SEGMENTS_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_socket.c b/src/libcharon/plugins/ha/ha_socket.c
index b84b02868..21e6eb6d5 100644
--- a/src/libcharon/plugins/ha/ha_socket.c
+++ b/src/libcharon/plugins/ha/ha_socket.c
@@ -58,8 +58,8 @@ struct private_ha_socket_t {
* Data to pass to the send_message() callback job
*/
typedef struct {
- ha_message_t *message;
- private_ha_socket_t *this;
+ chunk_t chunk;
+ int fd;
} job_data_t;
/**
@@ -67,7 +67,7 @@ typedef struct {
*/
static void job_data_destroy(job_data_t *this)
{
- this->message->destroy(this->message);
+ free(this->chunk.ptr);
free(this);
}
@@ -76,22 +76,15 @@ static void job_data_destroy(job_data_t *this)
*/
static job_requeue_t send_message(job_data_t *data)
{
- private_ha_socket_t *this;
- chunk_t chunk;
-
- this = data->this;
- chunk = data->message->get_encoding(data->message);
- if (send(this->fd, chunk.ptr, chunk.len, 0) < chunk.len)
+ if (send(data->fd, data->chunk.ptr, data->chunk.len, 0) < data->chunk.len)
{
DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
}
return JOB_REQUEUE_NONE;
}
-/**
- * Implementation of ha_socket_t.push
- */
-static void push(private_ha_socket_t *this, ha_message_t *message)
+METHOD(ha_socket_t, push, void,
+ private_ha_socket_t *this, ha_message_t *message)
{
chunk_t chunk;
@@ -107,9 +100,10 @@ static void push(private_ha_socket_t *this, ha_message_t *message)
/* Fallback to asynchronous transmission. This is required, as sendto()
* is a blocking call if it acquires a policy. We could end up in a
* deadlock, as we own an IKE_SA. */
- data = malloc_thing(job_data_t);
- data->message = message;
- data->this = this;
+ INIT(data,
+ .chunk = chunk_clone(chunk),
+ .fd = this->fd,
+ );
job = callback_job_create((callback_job_cb_t)send_message,
data, (void*)job_data_destroy, NULL);
@@ -118,13 +112,10 @@ static void push(private_ha_socket_t *this, ha_message_t *message)
}
DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
}
- message->destroy(message);
}
-/**
- * Implementation of ha_socket_t.pull
- */
-static ha_message_t *pull(private_ha_socket_t *this)
+METHOD(ha_socket_t, pull, ha_message_t*,
+ private_ha_socket_t *this)
{
while (TRUE)
{
@@ -189,10 +180,8 @@ static bool open_socket(private_ha_socket_t *this)
return TRUE;
}
-/**
- * Implementation of ha_socket_t.destroy.
- */
-static void destroy(private_ha_socket_t *this)
+METHOD(ha_socket_t, destroy, void,
+ private_ha_socket_t *this)
{
if (this->fd != -1)
{
@@ -208,15 +197,18 @@ static void destroy(private_ha_socket_t *this)
*/
ha_socket_t *ha_socket_create(char *local, char *remote)
{
- private_ha_socket_t *this = malloc_thing(private_ha_socket_t);
-
- this->public.push = (void(*)(ha_socket_t*, ha_message_t*))push;
- this->public.pull = (ha_message_t*(*)(ha_socket_t*))pull;
- this->public.destroy = (void(*)(ha_socket_t*))destroy;
+ private_ha_socket_t *this;
- this->local = host_create_from_dns(local, 0, HA_PORT);
- this->remote = host_create_from_dns(remote, 0, HA_PORT);
- this->fd = -1;
+ INIT(this,
+ .public = {
+ .push = _push,
+ .pull = _pull,
+ .destroy = _destroy,
+ },
+ .local = host_create_from_dns(local, 0, HA_PORT),
+ .remote = host_create_from_dns(remote, 0, HA_PORT),
+ .fd = -1,
+ );
if (!this->local || !this->remote)
{
diff --git a/src/libcharon/plugins/ha/ha_socket.h b/src/libcharon/plugins/ha/ha_socket.h
index 8d398e22b..a4789a51d 100644
--- a/src/libcharon/plugins/ha/ha_socket.h
+++ b/src/libcharon/plugins/ha/ha_socket.h
@@ -35,7 +35,7 @@ struct ha_socket_t {
/**
* Push synchronization information to the responsible node.
*
- * @param message message to send, gets destroyed by push()
+ * @param message message to send
*/
void (*push)(ha_socket_t *this, ha_message_t *message);
@@ -57,4 +57,4 @@ struct ha_socket_t {
*/
ha_socket_t *ha_socket_create(char *local, char *remote);
-#endif /* HA_SOCKET_ @}*/
+#endif /** HA_SOCKET_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c
index b3511e5f0..fef84a430 100644
--- a/src/libcharon/plugins/ha/ha_tunnel.c
+++ b/src/libcharon/plugins/ha/ha_tunnel.c
@@ -92,10 +92,8 @@ struct private_ha_tunnel_t {
ha_creds_t creds;
};
-/**
- * Implementation of ha_tunnel_t.is_sa
- */
-static bool is_sa(private_ha_tunnel_t *this, ike_sa_t *ike_sa)
+METHOD(ha_tunnel_t, is_sa, bool,
+ private_ha_tunnel_t *this, ike_sa_t *ike_sa)
{
peer_cfg_t *cfg = this->backend.cfg;
@@ -112,11 +110,8 @@ typedef struct {
shared_key_t *key;
} shared_enum_t;
-/**
- * Implementation of shared_enum_t.enumerate
- */
-static bool shared_enumerate(shared_enum_t *this, shared_key_t **key,
- id_match_t *me, id_match_t *other)
+METHOD(enumerator_t, shared_enumerate, bool,
+ shared_enum_t *this, shared_key_t **key, id_match_t *me, id_match_t *other)
{
if (this->key)
{
@@ -135,12 +130,9 @@ static bool shared_enumerate(shared_enum_t *this, shared_key_t **key,
return FALSE;
}
-/**
- * Implements ha_creds_t.create_shared_enumerator
- */
-static enumerator_t* create_shared_enumerator(ha_creds_t *this,
- shared_key_type_t type, identification_t *me,
- identification_t *other)
+METHOD(ha_creds_t, create_shared_enumerator, enumerator_t*,
+ ha_creds_t *this, shared_key_type_t type,
+ identification_t *me, identification_t *other)
{
shared_enum_t *enumerator;
@@ -157,28 +149,25 @@ static enumerator_t* create_shared_enumerator(ha_creds_t *this,
return NULL;
}
- enumerator = malloc_thing(shared_enum_t);
- enumerator->public.enumerate = (void*)shared_enumerate;
- enumerator->public.destroy = (void*)free;
- enumerator->key = this->key;
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_shared_enumerate,
+ .destroy = (void*)free,
+ },
+ .key = this->key,
+ );
return &enumerator->public;
}
-/**
- * Implementation of backend_t.create_peer_cfg_enumerator.
- */
-static enumerator_t* create_peer_cfg_enumerator(ha_backend_t *this,
- identification_t *me, identification_t *other)
+METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
+ ha_backend_t *this, identification_t *me, identification_t *other)
{
return enumerator_create_single(this->cfg, NULL);
}
-/**
- * Implementation of backend_t.create_ike_cfg_enumerator.
- */
-static enumerator_t* create_ike_cfg_enumerator(ha_backend_t *this,
- host_t *me, host_t *other)
+METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
+ ha_backend_t *this, host_t *me, host_t *other)
{
return enumerator_create_single(this->cfg->get_ike_cfg(this->cfg), NULL);
}
@@ -207,11 +196,11 @@ static void setup_tunnel(private_ha_tunnel_t *this,
chunk_clone(chunk_create(secret, strlen(secret))));
this->creds.public.create_private_enumerator = (void*)return_null;
this->creds.public.create_cert_enumerator = (void*)return_null;
- this->creds.public.create_shared_enumerator = (void*)create_shared_enumerator;
+ this->creds.public.create_shared_enumerator = (void*)_create_shared_enumerator;
this->creds.public.create_cdp_enumerator = (void*)return_null;
this->creds.public.cache_cert = (void*)nop;
- charon->credentials->add_set(charon->credentials, &this->creds.public);
+ lib->credmgr->add_set(lib->credmgr, &this->creds.public);
/* create config and backend */
ike_cfg = ike_cfg_create(FALSE, FALSE, local, IKEV2_UDP_PORT,
@@ -233,8 +222,9 @@ static void setup_tunnel(private_ha_tunnel_t *this,
identification_create_from_string(remote));
peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
- child_cfg = child_cfg_create("ha", &lifetime, NULL, TRUE,
- MODE_TRANSPORT, ACTION_NONE, ACTION_NONE, FALSE, 0);
+ child_cfg = child_cfg_create("ha", &lifetime, NULL, TRUE, MODE_TRANSPORT,
+ ACTION_NONE, ACTION_NONE, FALSE, 0, 0,
+ NULL, NULL);
ts = traffic_selector_create_dynamic(IPPROTO_UDP, HA_PORT, HA_PORT);
child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
ts = traffic_selector_create_dynamic(IPPROTO_ICMP, 0, 65535);
@@ -247,8 +237,8 @@ static void setup_tunnel(private_ha_tunnel_t *this,
peer_cfg->add_child_cfg(peer_cfg, child_cfg);
this->backend.cfg = peer_cfg;
- this->backend.public.create_peer_cfg_enumerator = (void*)create_peer_cfg_enumerator;
- this->backend.public.create_ike_cfg_enumerator = (void*)create_ike_cfg_enumerator;
+ this->backend.public.create_peer_cfg_enumerator = (void*)_create_peer_cfg_enumerator;
+ this->backend.public.create_ike_cfg_enumerator = (void*)_create_ike_cfg_enumerator;
this->backend.public.get_peer_cfg_by_name = (void*)return_null;
charon->backends->add_backend(charon->backends, &this->backend.public);
@@ -257,10 +247,8 @@ static void setup_tunnel(private_ha_tunnel_t *this,
this->trap = charon->traps->install(charon->traps, peer_cfg, child_cfg);
}
-/**
- * Implementation of ha_tunnel_t.destroy.
- */
-static void destroy(private_ha_tunnel_t *this)
+METHOD(ha_tunnel_t, destroy, void,
+ private_ha_tunnel_t *this)
{
if (this->backend.cfg)
{
@@ -269,7 +257,7 @@ static void destroy(private_ha_tunnel_t *this)
}
if (this->creds.key)
{
- charon->credentials->remove_set(charon->credentials, &this->creds.public);
+ lib->credmgr->remove_set(lib->credmgr, &this->creds.public);
this->creds.key->destroy(this->creds.key);
}
this->creds.local->destroy(this->creds.local);
@@ -286,10 +274,14 @@ static void destroy(private_ha_tunnel_t *this)
*/
ha_tunnel_t *ha_tunnel_create(char *local, char *remote, char *secret)
{
- private_ha_tunnel_t *this = malloc_thing(private_ha_tunnel_t);
+ private_ha_tunnel_t *this;
- this->public.is_sa = (bool(*)(ha_tunnel_t*, ike_sa_t *ike_sa))is_sa;
- this->public.destroy = (void(*)(ha_tunnel_t*))destroy;
+ INIT(this,
+ .public = {
+ .is_sa = _is_sa,
+ .destroy = _destroy,
+ },
+ );
setup_tunnel(this, local, remote, secret);
diff --git a/src/libcharon/plugins/ha/ha_tunnel.h b/src/libcharon/plugins/ha/ha_tunnel.h
index 085fb6122..549e33055 100644
--- a/src/libcharon/plugins/ha/ha_tunnel.h
+++ b/src/libcharon/plugins/ha/ha_tunnel.h
@@ -54,4 +54,4 @@ struct ha_tunnel_t {
*/
ha_tunnel_t *ha_tunnel_create(char *local, char *remote, char *secret);
-#endif /* HA_TUNNEL_H_ @}*/
+#endif /** HA_TUNNEL_H_ @}*/
diff --git a/src/libcharon/plugins/kernel_klips/Makefile.in b/src/libcharon/plugins/kernel_klips/Makefile.in
index f0d112a0f..9cac89ec3 100644
--- a/src/libcharon/plugins/kernel_klips/Makefile.in
+++ b/src/libcharon/plugins/kernel_klips/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.c b/src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.c
index 01df4f71a..6b5aeb342 100644
--- a/src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.c
+++ b/src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.c
@@ -1690,10 +1690,11 @@ static status_t group_ipip_sa(private_kernel_klips_ipsec_t *this,
METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi,
- protocol_id_t protocol, u_int32_t reqid, 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 encap,
- bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+ protocol_id_t protocol, u_int32_t reqid, mark_t mark,
+ 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 encap, bool inbound,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1849,7 +1850,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_klips_ipsec_t *this, u_int32_t spi, protocol_id_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)
+ bool encap, bool new_encap, mark_t mark)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1920,14 +1921,14 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t spi, protocol_id_t protocol, u_int64_t *bytes)
+ u_int32_t spi, protocol_id_t protocol, mark_t mark, u_int64_t *bytes)
{
return NOT_SUPPORTED; /* TODO */
}
METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t spi, protocol_id_t protocol, u_int16_t cpi)
+ u_int32_t spi, protocol_id_t protocol, u_int16_t cpi, mark_t mark)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1992,8 +1993,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t spi, protocol_id_t protocol,
- u_int32_t reqid, ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
- bool routed)
+ u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
+ u_int16_t cpi, bool routed)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -2210,7 +2211,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t *use_time)
+ traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
+ u_int32_t *use_time)
{
#define IDLE_PREFIX "idle="
static const char *path_eroute = "/proc/net/ipsec_eroute";
@@ -2365,7 +2367,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, bool unrouted)
+ traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
+ bool unrouted)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg = (struct sadb_msg*)request, *out;
@@ -2574,7 +2577,7 @@ METHOD(kernel_ipsec_t, destroy, void,
{
close(this->socket);
}
- if (this->socket_evnets > 0)
+ if (this->socket_events > 0)
{
close(this->socket_events);
}
diff --git a/src/libcharon/plugins/kernel_netlink/Makefile.in b/src/libcharon/plugins/kernel_netlink/Makefile.in
index 8c9965467..49cc895bc 100644
--- a/src/libcharon/plugins/kernel_netlink/Makefile.in
+++ b/src/libcharon/plugins/kernel_netlink/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
index 1b8c1b879..019ec93f8 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -280,6 +280,9 @@ struct policy_entry_t {
/** parameters of installed policy */
struct xfrm_selector sel;
+ /** optional mark */
+ u_int32_t mark;
+
/** associated route installed for this policy */
route_entry_t *route;
@@ -292,7 +295,8 @@ struct policy_entry_t {
*/
static u_int policy_hash(policy_entry_t *key)
{
- chunk_t chunk = chunk_create((void*)&key->sel, sizeof(struct xfrm_selector));
+ chunk_t chunk = chunk_create((void*)&key->sel,
+ sizeof(struct xfrm_selector) + sizeof(u_int32_t));
return chunk_hash(chunk);
}
@@ -301,7 +305,8 @@ static u_int policy_hash(policy_entry_t *key)
*/
static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)
{
- return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) &&
+ return memeq(&key->sel, &other_key->sel,
+ sizeof(struct xfrm_selector) + sizeof(u_int32_t)) &&
key->direction == other_key->direction;
}
@@ -917,11 +922,11 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t spi, protocol_id_t protocol, u_int32_t reqid,
+ u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, mark_t mark,
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 encap, bool inbound, traffic_selector_t* src_ts,
- traffic_selector_t* dst_ts)
+ u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+ u_int16_t cpi, bool encap, bool inbound,
+ traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
{
netlink_buf_t request;
char *alg_name;
@@ -934,8 +939,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
if (ipcomp != IPCOMP_NONE && cpi != 0)
{
lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};
- add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, &lft,
- ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty,
+ add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, mark,
+ &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty,
mode, ipcomp, 0, FALSE, inbound, NULL, NULL);
ipcomp = IPCOMP_NONE;
/* use transport mode ESP SA, IPComp uses tunnel mode */
@@ -944,9 +949,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
memset(&request, 0, sizeof(request));
- DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
- ntohl(spi), reqid);
-
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u} "
+ "(mark %u/0x%8x)", ntohl(spi), reqid, mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
+ ntohl(spi), reqid);
+ }
hdr = (struct nlmsghdr*)request;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
hdr->nlmsg_type = inbound ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
@@ -1151,6 +1163,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
if (encap)
{
+ struct xfrm_encap_tmpl *tmpl;
+
rthdr->rta_type = XFRMA_ENCAP;
rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
@@ -1160,7 +1174,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
return FAILED;
}
- struct xfrm_encap_tmpl* tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
+ tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
tmpl->encap_type = UDP_ENCAP_ESPINUDP;
tmpl->encap_sport = htons(src->get_port(src));
tmpl->encap_dport = htons(dst->get_port(dst));
@@ -1177,9 +1191,36 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
rthdr = XFRM_RTA_NEXT(rthdr);
}
+ if (mark.value)
+ {
+ struct xfrm_mark *mrk;
+
+ rthdr->rta_type = XFRMA_MARK;
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
+
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
+ mrk->v = mark.value;
+ mrk->m = mark.mask;
+ rthdr = XFRM_RTA_NEXT(rthdr);
+ }
+
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi));
+ if (mark.value)
+ {
+ DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x "
+ "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask);
+ }
+ else
+ {
+ DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi));
+ }
return FAILED;
}
return SUCCESS;
@@ -1275,7 +1316,7 @@ static status_t get_replay_state(private_kernel_netlink_ipsec_t *this,
METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t spi, protocol_id_t protocol, u_int64_t *bytes)
+ u_int32_t spi, protocol_id_t protocol, mark_t mark, u_int64_t *bytes)
{
netlink_buf_t request;
struct nlmsghdr *out = NULL, *hdr;
@@ -1285,8 +1326,15 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
memset(&request, 0, sizeof(request));
- DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi));
-
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "querying SAD entry with SPI %.8x (mark %u/0x%8x)",
+ ntohl(spi), mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi));
+ }
hdr = (struct nlmsghdr*)request;
hdr->nlmsg_flags = NLM_F_REQUEST;
hdr->nlmsg_type = XFRM_MSG_GETSA;
@@ -1298,6 +1346,24 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
sa_id->proto = proto_ike2kernel(protocol);
sa_id->family = dst->get_family(dst);
+ if (mark.value)
+ {
+ struct xfrm_mark *mrk;
+ struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
+
+ rthdr->rta_type = XFRMA_MARK;
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
+ mrk->v = mark.value;
+ mrk->m = mark.mask;
+ }
+
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
@@ -1313,8 +1379,20 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
case NLMSG_ERROR:
{
struct nlmsgerr *err = NLMSG_DATA(hdr);
- DBG1(DBG_KNL, "querying SAD entry with SPI %.8x failed: %s (%d)",
- ntohl(spi), strerror(-err->error), -err->error);
+
+ if (mark.value)
+ {
+ DBG1(DBG_KNL, "querying SAD entry with SPI %.8x "
+ "(mark %u/0x%8x) failed: %s (%d)",
+ ntohl(spi), mark.value, mark.mask,
+ strerror(-err->error), -err->error);
+ }
+ else
+ {
+ DBG1(DBG_KNL, "querying SAD entry with SPI %.8x "
+ "failed: %s (%d)", ntohl(spi),
+ strerror(-err->error), -err->error);
+ }
break;
}
default:
@@ -1341,7 +1419,7 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t spi, protocol_id_t protocol, u_int16_t cpi)
+ u_int32_t spi, protocol_id_t protocol, u_int16_t cpi, mark_t mark)
{
netlink_buf_t request;
struct nlmsghdr *hdr;
@@ -1350,13 +1428,20 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
/* if IPComp was used, we first delete the additional IPComp SA */
if (cpi)
{
- del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0);
+ del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0, mark);
}
memset(&request, 0, sizeof(request));
- DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi));
-
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x (mark %u/0x%8x)",
+ ntohl(spi), mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi));
+ }
hdr = (struct nlmsghdr*)request;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
hdr->nlmsg_type = XFRM_MSG_DELSA;
@@ -1368,19 +1453,53 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
sa_id->proto = proto_ike2kernel(protocol);
sa_id->family = dst->get_family(dst);
+ if (mark.value)
+ {
+ struct xfrm_mark *mrk;
+ struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
+
+ rthdr->rta_type = XFRMA_MARK;
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
+ mrk->v = mark.value;
+ mrk->m = mark.mask;
+ }
+
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi));
+ if (mark.value)
+ {
+ DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x "
+ "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask);
+ }
+ else
+ {
+ DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi));
+ }
return FAILED;
}
- DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi));
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%8x)",
+ ntohl(spi), mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi));
+ }
return SUCCESS;
}
METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_netlink_ipsec_t *this, u_int32_t spi, protocol_id_t protocol,
u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
- bool old_encap, bool new_encap)
+ bool old_encap, bool new_encap, mark_t mark)
{
netlink_buf_t request;
u_char *pos;
@@ -1398,7 +1517,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
if (cpi)
{
update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0,
- src, dst, new_src, new_dst, FALSE, FALSE);
+ src, dst, new_src, new_dst, FALSE, FALSE, mark);
}
memset(&request, 0, sizeof(request));
@@ -1459,7 +1578,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
}
/* delete the old SA (without affecting the IPComp SA) */
- if (del_sa(this, src, dst, spi, protocol, 0) != SUCCESS)
+ if (del_sa(this, src, dst, spi, protocol, 0, mark) != SUCCESS)
{
DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", ntohl(spi));
free(out);
@@ -1558,8 +1677,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t spi, protocol_id_t protocol,
- u_int32_t reqid, ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
- bool routed)
+ u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
+ u_int16_t cpi, bool routed)
{
policy_entry_t *current, *policy;
bool found = FALSE;
@@ -1571,6 +1690,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
policy = malloc_thing(policy_entry_t);
memset(policy, 0, sizeof(policy_entry_t));
policy->sel = ts2selector(src_ts, dst_ts);
+ policy->mark = mark.value & mark.mask;
policy->direction = direction;
/* find the policy, which matches EXACTLY */
@@ -1580,9 +1700,19 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
{
/* use existing policy */
current->refcount++;
- DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
- "refcount", src_ts, dst_ts,
- policy_dir_names, direction);
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%8x) "
+ "already exists, increasing refcount",
+ src_ts, dst_ts, policy_dir_names, direction,
+ mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "policy %R === %R %N "
+ "already exists, increasing refcount",
+ src_ts, dst_ts, policy_dir_names, direction);
+ }
free(policy);
policy = current;
found = TRUE;
@@ -1593,8 +1723,17 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
policy->refcount = 1;
}
- DBG2(DBG_KNL, "adding policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "adding policy %R === %R %N (mark %u/0x%8x)",
+ src_ts, dst_ts, policy_dir_names, direction,
+ mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "adding policy %R === %R %N",
+ src_ts, dst_ts, policy_dir_names, direction);
+ }
memset(&request, 0, sizeof(request));
hdr = (struct nlmsghdr*)request;
@@ -1673,6 +1812,25 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
tmpl->mode = mode2kernel(mode);
tmpl->family = src->get_family(src);
+ rthdr = XFRM_RTA_NEXT(rthdr);
+
+ if (mark.value)
+ {
+ struct xfrm_mark *mrk;
+
+ rthdr->rta_type = XFRMA_MARK;
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
+
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
+ mrk->v = mark.value;
+ mrk->m = mark.mask;
+ }
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
@@ -1741,7 +1899,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t *use_time)
+ traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
+ u_int32_t *use_time)
{
netlink_buf_t request;
struct nlmsghdr *out = NULL, *hdr;
@@ -1751,9 +1910,17 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
memset(&request, 0, sizeof(request));
- DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
-
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "querying policy %R === %R %N (mark %u/0x%8x)",
+ src_ts, dst_ts, policy_dir_names, direction,
+ mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts,
+ policy_dir_names, direction);
+ }
hdr = (struct nlmsghdr*)request;
hdr->nlmsg_flags = NLM_F_REQUEST;
hdr->nlmsg_type = XFRM_MSG_GETPOLICY;
@@ -1763,6 +1930,25 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
policy_id->sel = ts2selector(src_ts, dst_ts);
policy_id->dir = direction;
+ if (mark.value)
+ {
+ struct xfrm_mark *mrk;
+ struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
+
+ rthdr->rta_type = XFRMA_MARK;
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
+
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
+ mrk->v = mark.value;
+ mrk->m = mark.mask;
+ }
+
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
@@ -1816,7 +2002,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, bool unrouted)
+ traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
+ bool unrouted)
{
policy_entry_t *current, policy, *to_delete = NULL;
route_entry_t *route;
@@ -1824,12 +2011,22 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
struct nlmsghdr *hdr;
struct xfrm_userpolicy_id *policy_id;
- DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%8x)",
+ src_ts, dst_ts, policy_dir_names, direction,
+ mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "deleting policy %R === %R %N",
+ src_ts, dst_ts, policy_dir_names, direction);
+ }
/* create a policy */
memset(&policy, 0, sizeof(policy_entry_t));
policy.sel = ts2selector(src_ts, dst_ts);
+ policy.mark = mark.value & mark.mask;
policy.direction = direction;
/* find the policy */
@@ -1851,8 +2048,17 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
this->mutex->unlock(this->mutex);
if (!to_delete)
{
- DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts,
- dst_ts, policy_dir_names, direction);
+ if (mark.value)
+ {
+ DBG1(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%8x) "
+ "failed, not found", src_ts, dst_ts, policy_dir_names,
+ direction, mark.value, mark.mask);
+ }
+ else
+ {
+ DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found",
+ src_ts, dst_ts, policy_dir_names, direction);
+ }
return NOT_FOUND;
}
@@ -1867,13 +2073,40 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
policy_id->sel = to_delete->sel;
policy_id->dir = direction;
+ if (mark.value)
+ {
+ struct xfrm_mark *mrk;
+ struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
+
+ rthdr->rta_type = XFRMA_MARK;
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
+ mrk->v = mark.value;
+ mrk->m = mark.mask;
+ }
+
route = to_delete->route;
free(to_delete);
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to delete policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
+ if (mark.value)
+ {
+ DBG1(DBG_KNL, "unable to delete policy %R === %R %N "
+ "(mark %u/0x%8x)", src_ts, dst_ts, policy_dir_names,
+ direction, mark.value, mark.mask);
+ }
+ else
+ {
+ DBG1(DBG_KNL, "unable to delete policy %R === %R %N",
+ src_ts, dst_ts, policy_dir_names, direction);
+ }
return FAILED;
}
diff --git a/src/libcharon/plugins/kernel_pfkey/Makefile.in b/src/libcharon/plugins/kernel_pfkey/Makefile.in
index 2b028ba71..1dda6827b 100644
--- a/src/libcharon/plugins/kernel_pfkey/Makefile.in
+++ b/src/libcharon/plugins/kernel_pfkey/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
index 8a7883c8a..a64c27f6f 100644
--- a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
+++ b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008-2010 Tobias Brunner
* Copyright (C) 2008 Andreas Steffen
* Hochschule fuer Technik Rapperswil
*
@@ -67,8 +67,10 @@
/** non linux specific */
#ifndef IPPROTO_COMP
+#ifdef IPPROTO_IPCOMP
#define IPPROTO_COMP IPPROTO_IPCOMP
#endif
+#endif
#ifndef SADB_X_AALG_SHA2_256HMAC
#define SADB_X_AALG_SHA2_256HMAC SADB_X_AALG_SHA2_256
@@ -600,17 +602,43 @@ static int lookup_algorithm(kernel_algorithm_t *list, int ikev2)
}
/**
- * add a host behind a sadb_address extension
+ * Copy a host_t as sockaddr_t to the given memory location. Ports are
+ * reset to zero as per RFC 2367.
+ * @return the number of bytes copied
*/
-static void host2ext(host_t *host, struct sadb_address *ext)
+static size_t hostcpy(void *dest, host_t *host)
{
- sockaddr_t *host_addr = host->get_sockaddr(host);
+ sockaddr_t *addr = host->get_sockaddr(host), *dest_addr = dest;
socklen_t *len = host->get_sockaddr_len(host);
+ memcpy(dest, addr, *len);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
- host_addr->sa_len = *len;
+ dest_addr->sa_len = *len;
#endif
- memcpy((char*)(ext + 1), host_addr, *len);
- ext->sadb_address_len = PFKEY_LEN(sizeof(*ext) + *len);
+ switch (dest_addr->sa_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = dest;
+ sin->sin_port = 0;
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = dest;
+ sin6->sin6_port = 0;
+ break;
+ }
+ }
+ return *len;
+}
+
+/**
+ * add a host behind an sadb_address extension
+ */
+static void host2ext(host_t *host, struct sadb_address *ext)
+{
+ size_t len = hostcpy(ext + 1, host);
+ ext->sadb_address_len = PFKEY_LEN(sizeof(*ext) + len);
}
/**
@@ -1019,7 +1047,7 @@ static void process_migrate(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
}
#endif /*SADB_X_MIGRATE*/
-#ifdef HAVE_NATT
+#ifdef SADB_X_NAT_T_NEW_MAPPING
/**
* Process a SADB_X_NAT_T_NEW_MAPPING message from the kernel
*/
@@ -1075,7 +1103,7 @@ static void process_mapping(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
}
}
}
-#endif /*HAVE_NATT*/
+#endif /*SADB_X_NAT_T_NEW_MAPPING*/
/**
* Receives events from kernel
@@ -1137,11 +1165,11 @@ static job_requeue_t receive_events(private_kernel_pfkey_ipsec_t *this)
process_migrate(this, msg);
break;
#endif /*SADB_X_MIGRATE*/
-#ifdef HAVE_NATT
+#ifdef SADB_X_NAT_T_NEW_MAPPING
case SADB_X_NAT_T_NEW_MAPPING:
process_mapping(this, msg);
break;
-#endif /*HAVE_NATT*/
+#endif /*SADB_X_NAT_T_NEW_MAPPING*/
default:
break;
}
@@ -1217,10 +1245,11 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi,
- protocol_id_t protocol, u_int32_t reqid, 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 encap,
- bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+ protocol_id_t protocol, u_int32_t reqid, mark_t mark,
+ 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 encap, bool inbound,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1364,7 +1393,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_pfkey_ipsec_t *this, u_int32_t spi, protocol_id_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)
+ bool encap, bool new_encap, mark_t mark)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1497,7 +1526,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t spi, protocol_id_t protocol, u_int64_t *bytes)
+ u_int32_t spi, protocol_id_t protocol, mark_t mark, u_int64_t *bytes)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1553,7 +1582,7 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t spi, protocol_id_t protocol, u_int16_t cpi)
+ u_int32_t spi, protocol_id_t protocol, u_int16_t cpi, mark_t mark)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1604,8 +1633,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t spi, protocol_id_t protocol,
- u_int32_t reqid, ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
- bool routed)
+ u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
+ u_int16_t cpi, bool routed)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1679,14 +1708,10 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE;
if (mode == MODE_TUNNEL)
{
- sockaddr_t *sa;
- socklen_t sl;
- sa = src->get_sockaddr(src);
- sl = *src->get_sockaddr_len(src);
- memcpy(req + 1, sa, sl);
- sa = dst->get_sockaddr(dst);
- memcpy((u_int8_t*)(req + 1) + sl, sa, sl);
- req->sadb_x_ipsecrequest_len += sl * 2;
+ len = hostcpy(req + 1, src);
+ req->sadb_x_ipsecrequest_len += len;
+ len = hostcpy((char*)(req + 1) + len, dst);
+ req->sadb_x_ipsecrequest_len += len;
}
pol->sadb_x_policy_len += PFKEY_LEN(req->sadb_x_ipsecrequest_len);
@@ -1771,22 +1796,30 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
route->dst_net = chunk_clone(policy->src.net->get_address(policy->src.net));
route->prefixlen = policy->src.mask;
- switch (charon->kernel_interface->add_route(charon->kernel_interface,
- route->dst_net, route->prefixlen, route->gateway,
- route->src_ip, route->if_name))
+ if (route->if_name)
+ {
+ switch (charon->kernel_interface->add_route(
+ charon->kernel_interface, route->dst_net,
+ route->prefixlen, route->gateway,
+ route->src_ip, route->if_name))
+ {
+ default:
+ DBG1(DBG_KNL, "unable to install source route for %H",
+ route->src_ip);
+ /* FALL */
+ case ALREADY_DONE:
+ /* route exists, do not uninstall */
+ route_entry_destroy(route);
+ break;
+ case SUCCESS:
+ /* cache the installed route */
+ policy->route = route;
+ break;
+ }
+ }
+ else
{
- default:
- DBG1(DBG_KNL, "unable to install source route for %H",
- route->src_ip);
- /* FALL */
- case ALREADY_DONE:
- /* route exists, do not uninstall */
- route_entry_destroy(route);
- break;
- case SUCCESS:
- /* cache the installed route */
- policy->route = route;
- break;
+ route_entry_destroy(route);
}
}
else
@@ -1802,7 +1835,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t *use_time)
+ traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
+ u_int32_t *use_time)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1905,7 +1939,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, bool unrouted)
+ traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
+ bool unrouted)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
diff --git a/src/libcharon/plugins/kernel_pfroute/Makefile.in b/src/libcharon/plugins/kernel_pfroute/Makefile.in
index 3a4d2c3b5..f78a97013 100644
--- a/src/libcharon/plugins/kernel_pfroute/Makefile.in
+++ b/src/libcharon/plugins/kernel_pfroute/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/load_tester/Makefile.in b/src/libcharon/plugins/load_tester/Makefile.in
index 8965aff78..d049bb41b 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c
index c1f98f2fe..a230aa3f5 100644
--- a/src/libcharon/plugins/load_tester/load_tester_config.c
+++ b/src/libcharon/plugins/load_tester/load_tester_config.c
@@ -223,8 +223,9 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num)
generate_auth_cfg(this, this->initiator_auth, peer_cfg, FALSE, num);
}
- child_cfg = child_cfg_create("load-test", &lifetime, NULL, TRUE,
- MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE, 0);
+ child_cfg = child_cfg_create("load-test", &lifetime, NULL, TRUE, MODE_TUNNEL,
+ ACTION_NONE, ACTION_NONE, FALSE, 0, 0,
+ NULL, NULL);
proposal = proposal_create_from_string(PROTO_ESP, "aes128-sha1");
child_cfg->add_proposal(child_cfg, proposal);
ts = traffic_selector_create_dynamic(0, 0, 65535);
diff --git a/src/libcharon/plugins/load_tester/load_tester_ipsec.c b/src/libcharon/plugins/load_tester/load_tester_ipsec.c
index 1218443cc..43c0ef009 100644
--- a/src/libcharon/plugins/load_tester/load_tester_ipsec.c
+++ b/src/libcharon/plugins/load_tester/load_tester_ipsec.c
@@ -34,118 +34,89 @@ struct private_load_tester_ipsec_t {
u_int32_t spi;
};
-/**
- * Implementation of kernel_interface_t.get_spi.
- */
-static status_t get_spi(private_load_tester_ipsec_t *this,
- host_t *src, host_t *dst,
- protocol_id_t protocol, u_int32_t reqid,
- u_int32_t *spi)
+METHOD(kernel_ipsec_t, get_spi, status_t,
+ private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
+ protocol_id_t protocol, u_int32_t reqid, u_int32_t *spi)
{
*spi = ++this->spi;
return SUCCESS;
}
-/**
- * Implementation of kernel_interface_t.get_cpi.
- */
-static status_t get_cpi(private_load_tester_ipsec_t *this,
- host_t *src, host_t *dst,
- u_int32_t reqid, u_int16_t *cpi)
+METHOD(kernel_ipsec_t, get_cpi, status_t,
+ private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
+ u_int32_t reqid, u_int16_t *cpi)
{
return FAILED;
}
-/**
- * Implementation of kernel_interface_t.add_sa.
- */
-static status_t add_sa(private_load_tester_ipsec_t *this,
- host_t *src, host_t *dst, u_int32_t spi,
- protocol_id_t protocol, u_int32_t reqid,
- 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 encap, bool inbound, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts)
+METHOD(kernel_ipsec_t, add_sa, status_t,
+ private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
+ u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, mark_t mark,
+ 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 encap, bool inbound, traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts)
{
return SUCCESS;
}
-/**
- * Implementation of kernel_interface_t.update_sa.
- */
-static status_t update_sa(private_load_tester_ipsec_t *this,
- u_int32_t spi, protocol_id_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)
+METHOD(kernel_ipsec_t, update_sa, status_t,
+ private_load_tester_ipsec_t *this, u_int32_t spi, protocol_id_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)
{
return SUCCESS;
}
-/**
- * Implementation of kernel_interface_t.query_sa.
- */
-static status_t query_sa(private_load_tester_ipsec_t *this, host_t *src,
- host_t *dst, u_int32_t spi, protocol_id_t protocol,
- u_int64_t *bytes)
+METHOD(kernel_ipsec_t, query_sa, status_t,
+ private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
+ u_int32_t spi, protocol_id_t protocol, mark_t mark, u_int64_t *bytes)
{
return NOT_SUPPORTED;
}
-/**
- * Implementation of kernel_interface_t.del_sa.
- */
-static status_t del_sa(private_load_tester_ipsec_t *this, host_t *src,
- host_t *dst, u_int32_t spi, protocol_id_t protocol,
- u_int16_t cpi)
+METHOD(kernel_ipsec_t, del_sa, status_t,
+ private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
+ u_int32_t spi, protocol_id_t protocol, u_int16_t cpi, mark_t mark)
{
return SUCCESS;
}
-/**
- * Implementation of kernel_interface_t.add_policy.
- */
-static status_t add_policy(private_load_tester_ipsec_t *this,
- host_t *src, host_t *dst,
- traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts,
- policy_dir_t direction, u_int32_t spi,
- protocol_id_t protocol, u_int32_t reqid,
- ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
- bool routed)
+METHOD(kernel_ipsec_t, add_policy, status_t,
+ private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
+ policy_dir_t direction, u_int32_t spi, protocol_id_t protocol,
+ u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
+ u_int16_t cpi, bool routed)
{
return SUCCESS;
}
-/**
- * Implementation of kernel_interface_t.query_policy.
- */
-static status_t query_policy(private_load_tester_ipsec_t *this,
- traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts,
- policy_dir_t direction, u_int32_t *use_time)
+METHOD(kernel_ipsec_t, query_policy, status_t,
+ private_load_tester_ipsec_t *this, traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
+ u_int32_t *use_time)
{
*use_time = time_monotonic(NULL);
return SUCCESS;
}
-/**
- * Implementation of kernel_interface_t.del_policy.
- */
-static status_t del_policy(private_load_tester_ipsec_t *this,
- traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts,
- policy_dir_t direction, bool unrouted)
+METHOD(kernel_ipsec_t, del_policy, status_t,
+ private_load_tester_ipsec_t *this, traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
+ bool unrouted)
{
return SUCCESS;
}
-/**
- * Implementation of kernel_interface_t.destroy.
- */
-static void destroy(private_load_tester_ipsec_t *this)
+METHOD(kernel_ipsec_t, bypass_socket, bool,
+ private_load_tester_ipsec_t *this, int fd, int family)
+{
+ return TRUE;
+}
+
+METHOD(kernel_ipsec_t, destroy, void,
+ private_load_tester_ipsec_t *this)
{
free(this);
}
@@ -155,21 +126,26 @@ static void destroy(private_load_tester_ipsec_t *this)
*/
load_tester_ipsec_t *load_tester_ipsec_create()
{
- private_load_tester_ipsec_t *this = malloc_thing(private_load_tester_ipsec_t);
-
- /* public functions */
- this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
- this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi;
- this->public.interface.add_sa = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool,traffic_selector_t*,traffic_selector_t*))add_sa;
- this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,u_int16_t,host_t*,host_t*,host_t*,host_t*,bool,bool))update_sa;
- this->public.interface.query_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int64_t*))query_sa;
- this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int16_t))del_sa;
- this->public.interface.add_policy = (status_t(*)(kernel_ipsec_t *this,host_t *, host_t *,traffic_selector_t *,traffic_selector_t *,policy_dir_t, u_int32_t,protocol_id_t, u_int32_t,ipsec_mode_t, u_int16_t, u_int16_t,bool))add_policy;
- this->public.interface.query_policy = (status_t(*)(kernel_ipsec_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy;
- this->public.interface.del_policy = (status_t(*)(kernel_ipsec_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,bool))del_policy;
- this->public.interface.destroy = (void(*)(kernel_ipsec_t*)) destroy;
-
- this->spi = 0;
+ private_load_tester_ipsec_t *this;
+
+ INIT(this,
+ .public = {
+ .interface = {
+ .get_spi = _get_spi,
+ .get_cpi = _get_cpi,
+ .add_sa = _add_sa,
+ .update_sa = _update_sa,
+ .query_sa = _query_sa,
+ .del_sa = _del_sa,
+ .add_policy = _add_policy,
+ .query_policy = _query_policy,
+ .del_policy = _del_policy,
+ .bypass_socket = _bypass_socket,
+ .destroy = _destroy,
+ },
+ },
+ .spi = 0,
+ );
return &this->public;
}
diff --git a/src/libcharon/plugins/load_tester/load_tester_plugin.c b/src/libcharon/plugins/load_tester/load_tester_plugin.c
index 46145b803..15dbccb00 100644
--- a/src/libcharon/plugins/load_tester/load_tester_plugin.c
+++ b/src/libcharon/plugins/load_tester/load_tester_plugin.c
@@ -158,7 +158,7 @@ static void destroy(private_load_tester_plugin_t *this)
charon->kernel_interface->remove_ipsec_interface(charon->kernel_interface,
(kernel_ipsec_constructor_t)load_tester_ipsec_create);
charon->backends->remove_backend(charon->backends, &this->config->backend);
- charon->credentials->remove_set(charon->credentials, &this->creds->credential_set);
+ lib->credmgr->remove_set(lib->credmgr, &this->creds->credential_set);
charon->bus->remove_listener(charon->bus, &this->listener->listener);
this->config->destroy(this->config);
this->creds->destroy(this->creds);
@@ -209,7 +209,7 @@ plugin_t *load_tester_plugin_create()
this->creds = load_tester_creds_create();
this->listener = load_tester_listener_create(shutdown_on);
charon->backends->add_backend(charon->backends, &this->config->backend);
- charon->credentials->add_set(charon->credentials, &this->creds->credential_set);
+ lib->credmgr->add_set(lib->credmgr, &this->creds->credential_set);
charon->bus->add_listener(charon->bus, &this->listener->listener);
if (lib->settings->get_bool(lib->settings,
diff --git a/src/libcharon/plugins/medcli/Makefile.in b/src/libcharon/plugins/medcli/Makefile.in
index 539890ec3..c26d325a9 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c
index e355d55f7..6cbaf36f2 100644
--- a/src/libcharon/plugins/medcli/medcli_config.c
+++ b/src/libcharon/plugins/medcli/medcli_config.c
@@ -181,8 +181,9 @@ static peer_cfg_t *get_peer_cfg_by_name(private_medcli_config_t *this, char *nam
identification_create_from_encoding(ID_KEY_ID, other));
peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
- child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE,
- MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE, 0);
+ child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE, MODE_TUNNEL,
+ ACTION_NONE, ACTION_NONE, FALSE, 0, 0,
+ NULL, NULL);
child_cfg->add_proposal(child_cfg, proposal_create_default(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));
@@ -260,7 +261,8 @@ static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
this->current->add_auth_cfg(this->current, auth, FALSE);
child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE, MODE_TUNNEL,
- ACTION_NONE, ACTION_NONE, FALSE, 0);
+ ACTION_NONE, ACTION_NONE, FALSE, 0, 0,
+ NULL, NULL);
child_cfg->add_proposal(child_cfg, proposal_create_default(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));
diff --git a/src/libcharon/plugins/medcli/medcli_plugin.c b/src/libcharon/plugins/medcli/medcli_plugin.c
index 397168d46..6befbf440 100644
--- a/src/libcharon/plugins/medcli/medcli_plugin.c
+++ b/src/libcharon/plugins/medcli/medcli_plugin.c
@@ -61,7 +61,7 @@ static void destroy(private_medcli_plugin_t *this)
{
charon->bus->remove_listener(charon->bus, &this->listener->listener);
charon->backends->remove_backend(charon->backends, &this->config->backend);
- charon->credentials->remove_set(charon->credentials, &this->creds->set);
+ lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
this->listener->destroy(this->listener);
this->config->destroy(this->config);
this->creds->destroy(this->creds);
@@ -100,7 +100,7 @@ plugin_t *medcli_plugin_create()
this->config = medcli_config_create(this->db);
this->listener = medcli_listener_create(this->db);
- charon->credentials->add_set(charon->credentials, &this->creds->set);
+ lib->credmgr->add_set(lib->credmgr, &this->creds->set);
charon->backends->add_backend(charon->backends, &this->config->backend);
charon->bus->add_listener(charon->bus, &this->listener->listener);
diff --git a/src/libcharon/plugins/medsrv/Makefile.in b/src/libcharon/plugins/medsrv/Makefile.in
index a103a1340..4dc9c00d0 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/medsrv/medsrv_plugin.c b/src/libcharon/plugins/medsrv/medsrv_plugin.c
index 262d26d6b..c150346cb 100644
--- a/src/libcharon/plugins/medsrv/medsrv_plugin.c
+++ b/src/libcharon/plugins/medsrv/medsrv_plugin.c
@@ -54,7 +54,7 @@ struct private_medsrv_plugin_t {
static void destroy(private_medsrv_plugin_t *this)
{
charon->backends->remove_backend(charon->backends, &this->config->backend);
- charon->credentials->remove_set(charon->credentials, &this->creds->set);
+ lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
this->config->destroy(this->config);
this->creds->destroy(this->creds);
this->db->destroy(this->db);
@@ -91,7 +91,7 @@ plugin_t *medsrv_plugin_create()
this->creds = medsrv_creds_create(this->db);
this->config = medsrv_config_create(this->db);
- charon->credentials->add_set(charon->credentials, &this->creds->set);
+ lib->credmgr->add_set(lib->credmgr, &this->creds->set);
charon->backends->add_backend(charon->backends, &this->config->backend);
return &this->public.plugin;
diff --git a/src/libcharon/plugins/nm/Makefile.in b/src/libcharon/plugins/nm/Makefile.in
index c7f288f54..1b3e4c5a6 100644
--- a/src/libcharon/plugins/nm/Makefile.in
+++ b/src/libcharon/plugins/nm/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/nm/nm_plugin.c b/src/libcharon/plugins/nm/nm_plugin.c
index 6087f6589..250e6f7f9 100644
--- a/src/libcharon/plugins/nm/nm_plugin.c
+++ b/src/libcharon/plugins/nm/nm_plugin.c
@@ -84,7 +84,7 @@ static void destroy(private_nm_plugin_t *this)
{
g_object_unref(this->plugin);
}
- charon->credentials->remove_set(charon->credentials, &this->creds->set);
+ lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler);
this->creds->destroy(this->creds);
this->handler->destroy(this->handler);
@@ -110,7 +110,7 @@ plugin_t *nm_plugin_create()
this->creds = nm_creds_create();
this->handler = nm_handler_create();
hydra->attributes->add_handler(hydra->attributes, &this->handler->handler);
- charon->credentials->add_set(charon->credentials, &this->creds->set);
+ lib->credmgr->add_set(lib->credmgr, &this->creds->set);
this->plugin = nm_strongswan_plugin_new(this->creds, this->handler);
if (!this->plugin)
{
diff --git a/src/libcharon/plugins/nm/nm_service.c b/src/libcharon/plugins/nm/nm_service.c
index cdf7dc962..07318bbbf 100644
--- a/src/libcharon/plugins/nm/nm_service.c
+++ b/src/libcharon/plugins/nm/nm_service.c
@@ -444,7 +444,8 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
child_cfg = child_cfg_create(priv->name, &lifetime,
NULL, TRUE, MODE_TUNNEL, /* updown, hostaccess */
- ACTION_NONE, ACTION_NONE, ipcomp, 0);
+ ACTION_NONE, ACTION_NONE, ipcomp, 0, 0,
+ NULL, NULL);
child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
ts = traffic_selector_create_dynamic(0, 0, 65535);
child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
diff --git a/src/libcharon/plugins/resolve/Makefile.am b/src/libcharon/plugins/resolve/Makefile.am
deleted file mode 100644
index f8830d42e..000000000
--- a/src/libcharon/plugins/resolve/Makefile.am
+++ /dev/null
@@ -1,18 +0,0 @@
-
-INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
- -I$(top_srcdir)/src/libcharon
-
-AM_CFLAGS = -rdynamic \
- -DRESOLV_CONF=\"${resolv_conf}\"
-
-if MONOLITHIC
-noinst_LTLIBRARIES = libstrongswan-resolve.la
-else
-plugin_LTLIBRARIES = libstrongswan-resolve.la
-endif
-
-libstrongswan_resolve_la_SOURCES = \
- resolve_plugin.h resolve_plugin.c \
- resolve_handler.h resolve_handler.c
-
-libstrongswan_resolve_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/resolve/resolve_handler.c b/src/libcharon/plugins/resolve/resolve_handler.c
deleted file mode 100644
index 714c751a6..000000000
--- a/src/libcharon/plugins/resolve/resolve_handler.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "resolve_handler.h"
-
-#include <unistd.h>
-
-#include <daemon.h>
-#include <threading/mutex.h>
-
-typedef struct private_resolve_handler_t private_resolve_handler_t;
-
-/**
- * Private data of an resolve_handler_t object.
- */
-struct private_resolve_handler_t {
-
- /**
- * Public resolve_handler_t interface.
- */
- resolve_handler_t public;
-
- /**
- * resolv.conf file to use
- */
- char *file;
-
- /**
- * Mutex to access file exclusively
- */
- mutex_t *mutex;
-};
-
-/**
- * Implementation of attribute_handler_t.handle
- */
-static bool handle(private_resolve_handler_t *this, identification_t *server,
- configuration_attribute_type_t type, chunk_t data)
-{
- FILE *in, *out;
- char buf[1024];
- host_t *addr;
- size_t len;
- bool handled = FALSE;
-
- switch (type)
- {
- case INTERNAL_IP4_DNS:
- addr = host_create_from_chunk(AF_INET, data, 0);
- break;
- case INTERNAL_IP6_DNS:
- addr = host_create_from_chunk(AF_INET6, data, 0);
- break;
- default:
- return FALSE;
- }
-
- if (!addr || addr->is_anyaddr(addr))
- {
- DESTROY_IF(addr);
- return FALSE;
- }
- this->mutex->lock(this->mutex);
-
- in = fopen(this->file, "r");
- /* allows us to stream from in to out */
- unlink(this->file);
- out = fopen(this->file, "w");
- if (out)
- {
- fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr, server);
- DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
- handled = TRUE;
-
- /* copy rest of the file */
- if (in)
- {
- while ((len = fread(buf, 1, sizeof(buf), in)))
- {
- ignore_result(fwrite(buf, 1, len, out));
- }
- }
- fclose(out);
- }
- if (in)
- {
- fclose(in);
- }
- this->mutex->unlock(this->mutex);
- addr->destroy(addr);
-
- if (!handled)
- {
- DBG1(DBG_IKE, "adding DNS server failed", this->file);
- }
- return handled;
-}
-
-/**
- * Implementation of attribute_handler_t.release
- */
-static void release(private_resolve_handler_t *this, identification_t *server,
- configuration_attribute_type_t type, chunk_t data)
-{
- FILE *in, *out;
- char line[1024], matcher[512], *pos;
- host_t *addr;
- int family;
-
- switch (type)
- {
- case INTERNAL_IP4_DNS:
- family = AF_INET;
- break;
- case INTERNAL_IP6_DNS:
- family = AF_INET6;
- break;
- default:
- return;
- }
-
- this->mutex->lock(this->mutex);
-
- in = fopen(this->file, "r");
- if (in)
- {
- /* allows us to stream from in to out */
- unlink(this->file);
- out = fopen(this->file, "w");
- if (out)
- {
- addr = host_create_from_chunk(family, data, 0);
- snprintf(matcher, sizeof(matcher),
- "nameserver %H # by strongSwan, from %Y\n",
- addr, server);
-
- /* copy all, but matching line */
- while ((pos = fgets(line, sizeof(line), in)))
- {
- if (strneq(line, matcher, strlen(matcher)))
- {
- DBG1(DBG_IKE, "removing DNS server %H from %s",
- addr, this->file);
- }
- else
- {
- fputs(line, out);
- }
- }
- addr->destroy(addr);
- fclose(out);
- }
- fclose(in);
- }
-
- this->mutex->unlock(this->mutex);
-}
-
-/**
- * Attribute enumerator implementation
- */
-typedef struct {
- /** implements enumerator_t interface */
- enumerator_t public;
- /** virtual IP we are requesting */
- host_t *vip;
-} attribute_enumerator_t;
-
-/**
- * Implementation of create_attribute_enumerator().enumerate()
- */
-static bool attribute_enumerate(attribute_enumerator_t *this,
- configuration_attribute_type_t *type, chunk_t *data)
-{
- switch (this->vip->get_family(this->vip))
- {
- case AF_INET:
- *type = INTERNAL_IP4_DNS;
- break;
- case AF_INET6:
- *type = INTERNAL_IP6_DNS;
- break;
- default:
- return FALSE;
- }
- *data = chunk_empty;
- /* enumerate only once */
- this->public.enumerate = (void*)return_false;
- return TRUE;
-}
-
-/**
- * Implementation of attribute_handler_t.create_attribute_enumerator
- */
-static enumerator_t* create_attribute_enumerator(private_resolve_handler_t *this,
- identification_t *server, host_t *vip)
-{
- if (vip)
- {
- attribute_enumerator_t *enumerator;
-
- enumerator = malloc_thing(attribute_enumerator_t);
- enumerator->public.enumerate = (void*)attribute_enumerate;
- enumerator->public.destroy = (void*)free;
- enumerator->vip = vip;
-
- return &enumerator->public;
- }
- return enumerator_create_empty();
-}
-
-/**
- * Implementation of resolve_handler_t.destroy.
- */
-static void destroy(private_resolve_handler_t *this)
-{
- this->mutex->destroy(this->mutex);
- free(this);
-}
-
-/**
- * See header
- */
-resolve_handler_t *resolve_handler_create()
-{
- private_resolve_handler_t *this = malloc_thing(private_resolve_handler_t);
-
- this->public.handler.handle = (bool(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))handle;
- this->public.handler.release = (void(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))release;
- this->public.handler.create_attribute_enumerator = (enumerator_t*(*)(attribute_handler_t*, identification_t *server, host_t *vip))create_attribute_enumerator;
- this->public.destroy = (void(*)(resolve_handler_t*))destroy;
-
- this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
- this->file = lib->settings->get_str(lib->settings,
- "charon.plugins.resolve.file", RESOLV_CONF);
-
- return &this->public;
-}
-
diff --git a/src/libcharon/plugins/resolve/resolve_plugin.c b/src/libcharon/plugins/resolve/resolve_plugin.c
deleted file mode 100644
index 502129593..000000000
--- a/src/libcharon/plugins/resolve/resolve_plugin.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "resolve_plugin.h"
-#include "resolve_handler.h"
-
-#include <hydra.h>
-
-typedef struct private_resolve_plugin_t private_resolve_plugin_t;
-
-/**
- * private data of resolve plugin
- */
-struct private_resolve_plugin_t {
-
- /**
- * implements plugin interface
- */
- resolve_plugin_t public;
-
- /**
- * The registerd DNS attribute handler
- */
- resolve_handler_t *handler;
-};
-
-/**
- * Implementation of plugin_t.destroy
- */
-static void destroy(private_resolve_plugin_t *this)
-{
- hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler);
- this->handler->destroy(this->handler);
- free(this);
-}
-
-/*
- * see header file
- */
-plugin_t *resolve_plugin_create()
-{
- private_resolve_plugin_t *this = malloc_thing(private_resolve_plugin_t);
-
- this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
- this->handler = resolve_handler_create();
- hydra->attributes->add_handler(hydra->attributes, &this->handler->handler);
-
- return &this->public.plugin;
-}
-
diff --git a/src/libcharon/plugins/smp/Makefile.in b/src/libcharon/plugins/smp/Makefile.in
index b88283f38..35fb8367f 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/socket_default/Makefile.in b/src/libcharon/plugins/socket_default/Makefile.in
index 03c438acd..df63d862e 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/socket_dynamic/Makefile.in b/src/libcharon/plugins/socket_dynamic/Makefile.in
index 3a5fb3778..8a3a15188 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/socket_raw/Makefile.in b/src/libcharon/plugins/socket_raw/Makefile.in
index 65ad6a7a9..32bd9e0a1 100644
--- a/src/libcharon/plugins/socket_raw/Makefile.in
+++ b/src/libcharon/plugins/socket_raw/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/socket_raw/socket_raw_socket.c b/src/libcharon/plugins/socket_raw/socket_raw_socket.c
index e0155fa87..166870421 100644
--- a/src/libcharon/plugins/socket_raw/socket_raw_socket.c
+++ b/src/libcharon/plugins/socket_raw/socket_raw_socket.c
@@ -538,11 +538,12 @@ static int open_recv_socket(private_socket_raw_socket_t *this, int family)
/* Destination Port must be either port or natt_port */
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, udp_header + 2),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IKEV2_UDP_PORT, 1, 0),
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IKEV2_NATT_PORT, 5, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IKEV2_NATT_PORT, 6, 14),
/* port */
- /* IKE version must be 2.0 */
+ /* IKE version must be 2.x */
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + IKE_VERSION_OFFSET),
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10),
+ BPF_STMT(BPF_ALU+BPF_RSH+BPF_K, 4),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 2, 0, 11),
/* packet length is length in IKEv2 header + ip header + udp header */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + IKE_LENGTH_OFFSET),
BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN),
@@ -550,10 +551,11 @@ static int open_recv_socket(private_socket_raw_socket_t *this, int family)
/* natt_port */
/* nat-t: check for marker */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header),
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 5),
- /* nat-t: IKE version must be 2.0 */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 6),
+ /* nat-t: IKE version must be 2.x */
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + MARKER_LEN + IKE_VERSION_OFFSET),
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 3),
+ BPF_STMT(BPF_ALU+BPF_RSH+BPF_K, 4),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 2, 0, 3),
/* nat-t: packet length is length in IKEv2 header + ip header + udp header + non esp marker */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + MARKER_LEN + IKE_LENGTH_OFFSET),
BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN + MARKER_LEN),
diff --git a/src/libcharon/plugins/sql/Makefile.in b/src/libcharon/plugins/sql/Makefile.in
index 5803dc898..e32dc7b57 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c
index 23366898a..a47d93f7b 100644
--- a/src/libcharon/plugins/sql/sql_config.c
+++ b/src/libcharon/plugins/sql/sql_config.c
@@ -134,7 +134,7 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e)
.time = { .life = lifetime, .rekey = rekeytime, .jitter = jitter }
};
child_cfg = child_cfg_create(name, &lft, updown, hostaccess, mode,
- dpd, close, ipcomp, 0);
+ dpd, close, ipcomp, 0, 0, NULL, NULL);
/* TODO: read proposal from db */
child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
add_traffic_selectors(this, child_cfg, id);
diff --git a/src/libcharon/plugins/sql/sql_plugin.c b/src/libcharon/plugins/sql/sql_plugin.c
index e2d2d63b3..7b0a198d1 100644
--- a/src/libcharon/plugins/sql/sql_plugin.c
+++ b/src/libcharon/plugins/sql/sql_plugin.c
@@ -59,7 +59,7 @@ struct private_sql_plugin_t {
static void destroy(private_sql_plugin_t *this)
{
charon->backends->remove_backend(charon->backends, &this->config->backend);
- charon->credentials->remove_set(charon->credentials, &this->cred->set);
+ lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
charon->bus->remove_listener(charon->bus, &this->logger->listener);
this->config->destroy(this->config);
this->cred->destroy(this->cred);
@@ -99,7 +99,7 @@ plugin_t *sql_plugin_create()
this->logger = sql_logger_create(this->db);
charon->backends->add_backend(charon->backends, &this->config->backend);
- charon->credentials->add_set(charon->credentials, &this->cred->set);
+ lib->credmgr->add_set(lib->credmgr, &this->cred->set);
charon->bus->add_listener(charon->bus, &this->logger->listener);
return &this->public.plugin;
diff --git a/src/libcharon/plugins/stroke/Makefile.in b/src/libcharon/plugins/stroke/Makefile.in
index 8815ba741..e094200ca 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/stroke/stroke_ca.c b/src/libcharon/plugins/stroke/stroke_ca.c
index 49146f18b..9a3ae0ab9 100644
--- a/src/libcharon/plugins/stroke/stroke_ca.c
+++ b/src/libcharon/plugins/stroke/stroke_ca.c
@@ -306,7 +306,8 @@ static void del(private_stroke_ca_t *this, stroke_msg_t *msg)
return;
}
ca_section_destroy(ca);
- /* TODO: flush cached certs */
+
+ lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
}
/**
@@ -356,12 +357,16 @@ static void check_for_hash_and_url(private_stroke_ca_t *this, certificate_t* cer
{
if (section->certuribase && cert->issued_by(cert, section->cert))
{
- chunk_t hash, encoded = cert->get_encoding(cert);
- hasher->allocate_hash(hasher, encoded, &hash);
- section->hashes->insert_last(section->hashes,
- identification_create_from_encoding(ID_KEY_ID, hash));
- chunk_free(&hash);
- chunk_free(&encoded);
+ chunk_t hash, encoded;
+
+ if (cert->get_encoding(cert, CERT_ASN1_DER, &encoded))
+ {
+ hasher->allocate_hash(hasher, encoded, &hash);
+ section->hashes->insert_last(section->hashes,
+ identification_create_from_encoding(ID_KEY_ID, hash));
+ chunk_free(&hash);
+ chunk_free(&encoded);
+ }
break;
}
}
@@ -400,11 +405,11 @@ static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
/* list authkey and keyid */
if (public)
{
- if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
+ if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
{
fprintf(out, " authkey: %#B\n", &chunk);
}
- if (public->get_fingerprint(public, KEY_ID_PUBKEY_INFO_SHA1, &chunk))
+ if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &chunk))
{
fprintf(out, " keyid: %#B\n", &chunk);
}
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index bbc1e7a31..617069432 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -399,8 +399,8 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
if (ca)
{
identity = identification_create_from_string(ca);
- certificate = charon->credentials->get_cert(charon->credentials,
- CERT_X509, KEY_ANY, identity, TRUE);
+ certificate = lib->credmgr->get_cert(lib->credmgr, CERT_X509,
+ KEY_ANY, identity, TRUE);
identity->destroy(identity);
if (certificate)
{
@@ -413,7 +413,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
}
}
- /* AC groups */
+ /* groups */
if (end->groups)
{
enumerator_t *enumerator;
@@ -422,9 +422,8 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
enumerator = enumerator_create_token(end->groups, ",", " ");
while (enumerator->enumerate(enumerator, &group))
{
- identity = identification_create_from_encoding(ID_IETF_ATTR_STRING,
- chunk_create(group, strlen(group)));
- cfg->add(cfg, AUTH_RULE_AC_GROUP, identity);
+ cfg->add(cfg, AUTH_RULE_GROUP,
+ identification_create_from_string(group));
}
enumerator->destroy(enumerator);
}
@@ -769,6 +768,14 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
.jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100
}
};
+ mark_t mark_in = {
+ .value = msg->add_conn.mark_in.value,
+ .mask = msg->add_conn.mark_in.mask
+ };
+ mark_t mark_out = {
+ .value = msg->add_conn.mark_out.value,
+ .mask = msg->add_conn.mark_out.mask
+ };
switch (msg->add_conn.dpd.action)
{ /* map startes magic values to our action type */
@@ -787,7 +794,8 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
msg->add_conn.name, &lifetime,
msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
msg->add_conn.mode, dpd, dpd, msg->add_conn.ipcomp,
- msg->add_conn.inactivity);
+ msg->add_conn.inactivity, msg->add_conn.reqid,
+ &mark_in, &mark_out);
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_control.c b/src/libcharon/plugins/stroke/stroke_control.c
index a03aef697..f64421551 100644
--- a/src/libcharon/plugins/stroke/stroke_control.c
+++ b/src/libcharon/plugins/stroke/stroke_control.c
@@ -186,6 +186,11 @@ static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *o
}
else
{
+ if (!pos)
+ {
+ DBG1(DBG_CFG, "error parsing string");
+ return;
+ }
if (*(pos + 1) == '*')
{ /* is name[*] */
all = TRUE;
diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c
index e0a5210a9..2816b9bb2 100644
--- a/src/libcharon/plugins/stroke/stroke_cred.c
+++ b/src/libcharon/plugins/stroke/stroke_cred.c
@@ -378,7 +378,7 @@ static bool add_crl(private_stroke_cred_t *this, crl_t* crl)
}
if (found)
{
- new = cert->is_newer(cert, current);
+ new = crl_is_newer(crl, crl_c);
if (new)
{
this->certs->remove_at(this->certs, enumerator);
@@ -587,9 +587,11 @@ static void cache_cert(private_stroke_cred_t *this, certificate_t *cert)
snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_DIR, hex);
free(hex.ptr);
- chunk = cert->get_encoding(cert);
- chunk_write(chunk, buf, "crl", 022, TRUE);
- free(chunk.ptr);
+ if (cert->get_encoding(cert, CERT_ASN1_DER, &chunk))
+ {
+ chunk_write(chunk, buf, "crl", 022, TRUE);
+ free(chunk.ptr);
+ }
}
}
}
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index c2a98da33..a6de35466 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -17,6 +17,10 @@
#include <time.h>
+#ifdef HAVE_MALLINFO
+#include <malloc.h>
+#endif /* HAVE_MALLINFO */
+
#include <daemon.h>
#include <utils/linked_list.h>
#include <credentials/certificates/x509.h>
@@ -55,6 +59,33 @@ struct private_stroke_list_t {
};
/**
+ * Log tasks of a specific queue to out
+ */
+static void log_task_q(FILE *out, 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)
+ {
+ fprintf(out, "%12s[%d]: Tasks %s: ", ike_sa->get_name(ike_sa),
+ ike_sa->get_unique_id(ike_sa), name);
+ has = TRUE;
+ }
+ fprintf(out, "%N ", task_type_names, task->get_type(task));
+ }
+ enumerator->destroy(enumerator);
+ if (has)
+ {
+ fprintf(out, "\n");
+ }
+}
+
+/**
* log an IKE_SA to out
*/
static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
@@ -140,6 +171,10 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
buf+4);
}
+
+ log_task_q(out, ike_sa, TASK_QUEUE_QUEUED, "queued");
+ log_task_q(out, ike_sa, TASK_QUEUE_ACTIVE, "active");
+ log_task_q(out, ike_sa, TASK_QUEUE_PASSIVE, "passive");
}
}
@@ -342,7 +377,7 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local)
rules = auth->create_enumerator(auth);
while (rules->enumerate(rules, &rule, &id))
{
- if (rule == AUTH_RULE_AC_GROUP)
+ if (rule == AUTH_RULE_GROUP)
{
fprintf(out, "%12s: group: %Y\n", name, id);
}
@@ -373,12 +408,19 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo
u_int32_t dpd;
time_t since, now;
u_int size, online, offline;
-
now = time_monotonic(NULL);
since = time(NULL) - (now - this->uptime);
fprintf(out, "Status of IKEv2 charon daemon (strongSwan "VERSION"):\n");
fprintf(out, " uptime: %V, since %T\n", &now, &this->uptime, &since, FALSE);
+#ifdef HAVE_MALLINFO
+ {
+ struct mallinfo mi = mallinfo();
+
+ fprintf(out, " malloc: sbrk %d, mmap %d, used %d, free %d\n",
+ mi.arena, mi.hblkhd, mi.uordblks, mi.fordblks);
+ }
+#endif /* HAVE_MALLINFO */
fprintf(out, " worker threads: %d idle of %d,",
charon->processor->get_idle_threads(charon->processor),
charon->processor->get_total_threads(charon->processor));
@@ -534,9 +576,8 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo
static linked_list_t* create_unique_cert_list(certificate_type_t type)
{
linked_list_t *list = linked_list_create();
- enumerator_t *enumerator = charon->credentials->create_cert_enumerator(
- charon->credentials, type, KEY_ANY,
- NULL, FALSE);
+ enumerator_t *enumerator = lib->credmgr->create_cert_enumerator(
+ lib->credmgr, type, KEY_ANY, NULL, FALSE);
certificate_t *cert;
while (enumerator->enumerate(enumerator, (void**)&cert))
@@ -585,11 +626,11 @@ static void list_public_key(public_key_t *public, FILE *out)
identification_t *id;
auth_cfg_t *auth;
- if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &keyid))
+ if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))
{
id = identification_create_from_encoding(ID_KEY_ID, keyid);
auth = auth_cfg_create();
- private = charon->credentials->get_private(charon->credentials,
+ private = lib->credmgr->get_private(lib->credmgr,
public->get_type(public), id, auth);
auth->destroy(auth);
id->destroy(id);
@@ -599,11 +640,11 @@ static void list_public_key(public_key_t *public, FILE *out)
key_type_names, public->get_type(public),
public->get_keysize(public) * 8,
private ? ", has private key" : "");
- if (public->get_fingerprint(public, KEY_ID_PUBKEY_INFO_SHA1, &keyid))
+ if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
{
fprintf(out, " keyid: %#B\n", &keyid);
}
- if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &keyid))
+ if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))
{
fprintf(out, " subjkey: %#B\n", &keyid);
}
diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c
index 56c18da38..18afa5af4 100644
--- a/src/libcharon/plugins/stroke/stroke_socket.c
+++ b/src/libcharon/plugins/stroke/stroke_socket.c
@@ -344,8 +344,7 @@ static void stroke_purge(private_stroke_socket_t *this,
{
if (msg->purge.flags & PURGE_OCSP)
{
- charon->credentials->flush_cache(charon->credentials,
- CERT_X509_OCSP_RESPONSE);
+ lib->credmgr->flush_cache(lib->credmgr, CERT_X509_OCSP_RESPONSE);
}
if (msg->purge.flags & PURGE_IKE)
{
@@ -622,8 +621,8 @@ static bool open_socket(private_stroke_socket_t *this)
static void destroy(private_stroke_socket_t *this)
{
this->job->cancel(this->job);
- charon->credentials->remove_set(charon->credentials, &this->ca->set);
- charon->credentials->remove_set(charon->credentials, &this->cred->set);
+ lib->credmgr->remove_set(lib->credmgr, &this->ca->set);
+ lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
charon->backends->remove_backend(charon->backends, &this->config->backend);
hydra->attributes->remove_provider(hydra->attributes, &this->attribute->provider);
this->cred->destroy(this->cred);
@@ -657,8 +656,8 @@ stroke_socket_t *stroke_socket_create()
this->control = stroke_control_create();
this->list = stroke_list_create(this->attribute);
- charon->credentials->add_set(charon->credentials, &this->ca->set);
- charon->credentials->add_set(charon->credentials, &this->cred->set);
+ lib->credmgr->add_set(lib->credmgr, &this->ca->set);
+ lib->credmgr->add_set(lib->credmgr, &this->cred->set);
charon->backends->add_backend(charon->backends, &this->config->backend);
hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider);
diff --git a/src/libcharon/plugins/uci/Makefile.in b/src/libcharon/plugins/uci/Makefile.in
index c10829bb3..934ab6080 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c
index bd58afbf0..ddddae782 100644
--- a/src/libcharon/plugins/uci/uci_config.c
+++ b/src/libcharon/plugins/uci/uci_config.c
@@ -196,7 +196,8 @@ static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
this->peer_cfg->add_auth_cfg(this->peer_cfg, auth, FALSE);
child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE, MODE_TUNNEL,
- ACTION_NONE, ACTION_NONE, FALSE, 0);
+ ACTION_NONE, ACTION_NONE, FALSE, 0, 0,
+ NULL, NULL);
child_cfg->add_proposal(child_cfg, create_proposal(esp_proposal, PROTO_ESP));
child_cfg->add_traffic_selector(child_cfg, TRUE, create_ts(local_net));
child_cfg->add_traffic_selector(child_cfg, FALSE, create_ts(remote_net));
diff --git a/src/libcharon/plugins/uci/uci_plugin.c b/src/libcharon/plugins/uci/uci_plugin.c
index 742fcf4d0..4790ef4e7 100644
--- a/src/libcharon/plugins/uci/uci_plugin.c
+++ b/src/libcharon/plugins/uci/uci_plugin.c
@@ -64,7 +64,7 @@ struct private_uci_plugin_t {
static void destroy(private_uci_plugin_t *this)
{
charon->backends->remove_backend(charon->backends, &this->config->backend);
- charon->credentials->remove_set(charon->credentials, &this->creds->credential_set);
+ lib->credmgr->remove_set(lib->credmgr, &this->creds->credential_set);
this->config->destroy(this->config);
this->creds->destroy(this->creds);
this->parser->destroy(this->parser);
@@ -86,7 +86,7 @@ plugin_t *uci_plugin_create()
this->creds = uci_creds_create(this->parser);
this->control = uci_control_create();
charon->backends->add_backend(charon->backends, &this->config->backend);
- charon->credentials->add_set(charon->credentials, &this->creds->credential_set);
+ lib->credmgr->add_set(lib->credmgr, &this->creds->credential_set);
return &this->public.plugin;
}
diff --git a/src/libcharon/plugins/unit_tester/Makefile.am b/src/libcharon/plugins/unit_tester/Makefile.am
index e27d1f859..c46d2b85d 100644
--- a/src/libcharon/plugins/unit_tester/Makefile.am
+++ b/src/libcharon/plugins/unit_tester/Makefile.am
@@ -24,6 +24,7 @@ libstrongswan_unit_tester_la_SOURCES = \
tests/test_chunk.c \
tests/test_pool.c \
tests/test_agent.c \
- tests/test_id.c
+ tests/test_id.c \
+ tests/test_hashtable.c
libstrongswan_unit_tester_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/unit_tester/Makefile.in b/src/libcharon/plugins/unit_tester/Makefile.in
index 6ca43a38f..47850c1c5 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -78,7 +78,7 @@ am_libstrongswan_unit_tester_la_OBJECTS = unit_tester.lo \
test_enumerator.lo test_auth_info.lo test_curl.lo \
test_mysql.lo test_sqlite.lo test_mutex.lo test_rsa_gen.lo \
test_cert.lo test_med_db.lo test_chunk.lo test_pool.lo \
- test_agent.lo test_id.lo
+ test_agent.lo test_id.lo test_hashtable.lo
libstrongswan_unit_tester_la_OBJECTS = \
$(am_libstrongswan_unit_tester_la_OBJECTS)
libstrongswan_unit_tester_la_LINK = $(LIBTOOL) --tag=CC \
@@ -281,7 +281,8 @@ libstrongswan_unit_tester_la_SOURCES = \
tests/test_chunk.c \
tests/test_pool.c \
tests/test_agent.c \
- tests/test_id.c
+ tests/test_id.c \
+ tests/test_hashtable.c
libstrongswan_unit_tester_la_LDFLAGS = -module -avoid-version
all: all-am
@@ -373,6 +374,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_chunk.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_curl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_enumerator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hashtable.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_id.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_med_db.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mutex.Plo@am__quote@
@@ -494,6 +496,13 @@ test_id.lo: tests/test_id.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_id.lo `test -f 'tests/test_id.c' || echo '$(srcdir)/'`tests/test_id.c
+test_hashtable.lo: tests/test_hashtable.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_hashtable.lo -MD -MP -MF $(DEPDIR)/test_hashtable.Tpo -c -o test_hashtable.lo `test -f 'tests/test_hashtable.c' || echo '$(srcdir)/'`tests/test_hashtable.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_hashtable.Tpo $(DEPDIR)/test_hashtable.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/test_hashtable.c' object='test_hashtable.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_hashtable.lo `test -f 'tests/test_hashtable.c' || echo '$(srcdir)/'`tests/test_hashtable.c
+
mostlyclean-libtool:
-rm -f *.lo
diff --git a/src/libcharon/plugins/unit_tester/tests.h b/src/libcharon/plugins/unit_tester/tests.h
index 96313d390..cd38c8a99 100644
--- a/src/libcharon/plugins/unit_tester/tests.h
+++ b/src/libcharon/plugins/unit_tester/tests.h
@@ -19,6 +19,7 @@
*/
DEFINE_TEST("linked_list_t->remove()", test_list_remove, FALSE)
+DEFINE_TEST("hashtable_t->remove_at()", test_hashtable_remove_at, FALSE)
DEFINE_TEST("simple enumerator", test_enumerate, FALSE)
DEFINE_TEST("nested enumerator", test_enumerate_nested, FALSE)
DEFINE_TEST("filtered enumerator", test_enumerate_filtered, FALSE)
diff --git a/src/libcharon/plugins/unit_tester/tests/test_auth_info.c b/src/libcharon/plugins/unit_tester/tests/test_auth_info.c
index d6abe7a05..c250c356f 100644
--- a/src/libcharon/plugins/unit_tester/tests/test_auth_info.c
+++ b/src/libcharon/plugins/unit_tester/tests/test_auth_info.c
@@ -15,7 +15,7 @@
#include <daemon.h>
#include <library.h>
-#include <config/auth_cfg.h>
+#include <credentials/auth_cfg.h>
static chunk_t certchunk = chunk_from_chars(
diff --git a/src/libcharon/plugins/unit_tester/tests/test_hashtable.c b/src/libcharon/plugins/unit_tester/tests/test_hashtable.c
new file mode 100644
index 000000000..bd79e12f7
--- /dev/null
+++ b/src/libcharon/plugins/unit_tester/tests/test_hashtable.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <library.h>
+#include <utils/hashtable.h>
+
+static u_int hash(char *key)
+{
+ return chunk_hash(chunk_create(key, strlen(key)));
+}
+
+static u_int equals(char *key1, char *key2)
+{
+ return streq(key1, key2);
+}
+
+/**
+ * Test the remove_at method
+ */
+bool test_hashtable_remove_at()
+{
+ char *k1 = "key1", *k2 = "key2", *k3 = "key3", *key;
+ char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value;
+ enumerator_t *enumerator;
+ hashtable_t *ht = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 0);
+
+ ht->put(ht, k1, v1);
+ ht->put(ht, k2, v2);
+ ht->put(ht, k3, v3);
+
+ if (ht->get_count(ht) != 3)
+ {
+ return FALSE;
+ }
+
+ enumerator = ht->create_enumerator(ht);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ if (streq(key, k2))
+ {
+ ht->remove_at(ht, enumerator);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (ht->get_count(ht) != 2)
+ {
+ return FALSE;
+ }
+
+ if (ht->get(ht, k1) == NULL ||
+ ht->get(ht, k3) == NULL)
+ {
+ return FALSE;
+ }
+
+ if (ht->get(ht, k2) != NULL)
+ {
+ return FALSE;
+ }
+
+ ht->put(ht, k2, v2);
+
+ if (ht->get_count(ht) != 3)
+ {
+ return FALSE;
+ }
+
+ if (ht->get(ht, k1) == NULL ||
+ ht->get(ht, k2) == NULL ||
+ ht->get(ht, k3) == NULL)
+ {
+ return FALSE;
+ }
+
+ enumerator = ht->create_enumerator(ht);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ ht->remove_at(ht, enumerator);
+ }
+ enumerator->destroy(enumerator);
+
+ if (ht->get_count(ht) != 0)
+ {
+ return FALSE;
+ }
+
+ if (ht->get(ht, k1) != NULL ||
+ ht->get(ht, k2) != NULL ||
+ ht->get(ht, k3) != NULL)
+ {
+ return FALSE;
+ }
+
+ ht->destroy(ht);
+
+ return TRUE;
+}
diff --git a/src/libcharon/plugins/unit_tester/tests/test_med_db.c b/src/libcharon/plugins/unit_tester/tests/test_med_db.c
index 7fd78b0bc..ae1d08e15 100644
--- a/src/libcharon/plugins/unit_tester/tests/test_med_db.c
+++ b/src/libcharon/plugins/unit_tester/tests/test_med_db.c
@@ -37,11 +37,11 @@ bool test_med_db()
bool good = FALSE;
id = identification_create_from_encoding(ID_KEY_ID, keyid);
- enumerator = charon->credentials->create_public_enumerator(
- charon->credentials, KEY_ANY, id, NULL);
+ enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
+ KEY_ANY, id, NULL);
while (enumerator->enumerate(enumerator, &public, &auth))
{
- good = public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &found);
+ good = public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &found);
if (good)
{
good = chunk_equals(id->get_encoding(id), found);
diff --git a/src/libcharon/plugins/updown/Makefile.in b/src/libcharon/plugins/updown/Makefile.in
index d3c509a32..ce233ad04 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.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c
index 5a6746f92..ea4a792c2 100644
--- a/src/libcharon/plugins/updown/updown_listener.c
+++ b/src/libcharon/plugins/updown/updown_listener.c
@@ -115,7 +115,8 @@ METHOD(listener_t, child_updown, bool,
{
char command[1024];
char *my_client, *other_client, *my_client_mask, *other_client_mask;
- char *pos, *virtual_ip, *iface;
+ char *pos, *virtual_ip, *iface, *mark_in, *mark_out, *udp_enc;
+ mark_t mark;
bool is_host, is_ipv6;
FILE *shell;
@@ -160,6 +161,61 @@ METHOD(listener_t, child_updown, bool,
}
}
+ /* check for the presence of an inbound mark */
+ mark = config->get_mark(config, TRUE);
+ if (mark.value)
+ {
+ if (asprintf(&mark_in, "PLUTO_MARK_IN='%u/0x%08x' ",
+ mark.value, mark.mask ) < 0)
+ {
+ mark_in = NULL;
+ }
+ }
+ else
+ {
+ if (asprintf(&mark_in, "") < 0)
+ {
+ mark_in = NULL;
+ }
+ }
+
+ /* check for the presence of an outbound mark */
+ mark = config->get_mark(config, FALSE);
+ if (mark.value)
+ {
+ if (asprintf(&mark_out, "PLUTO_MARK_OUT='%u/0x%08x' ",
+ mark.value, mark.mask ) < 0)
+ {
+ mark_out = NULL;
+ }
+ }
+ else
+ {
+ if (asprintf(&mark_out, "") < 0)
+ {
+ mark_out = NULL;
+ }
+ }
+
+ /* check for a NAT condition causing ESP_IN_UDP encapsulation */
+ if (ike_sa->has_condition(ike_sa, COND_NAT_ANY))
+ {
+ if (asprintf(&udp_enc, "PLUTO_UDP_ENC='%u' ",
+ other->get_port(other)) < 0)
+ {
+ udp_enc = NULL;
+ }
+
+ }
+ else
+ {
+ if (asprintf(&udp_enc, "") < 0)
+ {
+ udp_enc = NULL;
+ }
+
+ }
+
if (up)
{
iface = charon->kernel_interface->get_interface(
@@ -205,6 +261,9 @@ METHOD(listener_t, child_updown, bool,
"PLUTO_PEER_PROTOCOL='%u' "
"%s"
"%s"
+ "%s"
+ "%s"
+ "%s"
"%s",
up ? "up" : "down",
is_host ? "-host" : "-client",
@@ -223,11 +282,17 @@ METHOD(listener_t, child_updown, bool,
other_ts->get_from_port(other_ts),
other_ts->get_protocol(other_ts),
virtual_ip,
+ mark_in,
+ mark_out,
+ udp_enc,
config->get_hostaccess(config) ? "PLUTO_HOST_ACCESS='1' " : "",
script);
free(my_client);
free(other_client);
free(virtual_ip);
+ free(mark_in);
+ free(mark_out);
+ free(udp_enc);
free(iface);
DBG3(DBG_CHD, "running updown script: %s", command);
@@ -283,7 +348,9 @@ updown_listener_t *updown_listener_create()
INIT(this,
.public = {
- .listener.child_updown = _child_updown,
+ .listener = {
+ .child_updown = _child_updown,
+ },
.destroy = _destroy,
},
.iface_cache = linked_list_create(),