summaryrefslogtreecommitdiff
path: root/src/charon
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2008-02-07 13:56:17 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2008-02-07 13:56:17 +0000
commitbcc8f7ca7fd8e8ff6e8a4d579251458313133598 (patch)
treea86b42b486c954937b32ffeaaa725804cb1458ec /src/charon
parent49104abddf3d71d5abf5cf75dc7f95fa6c55fa63 (diff)
downloadvyos-strongswan-bcc8f7ca7fd8e8ff6e8a4d579251458313133598.tar.gz
vyos-strongswan-bcc8f7ca7fd8e8ff6e8a4d579251458313133598.zip
[svn-upgrade] Integrating new upstream version, strongswan (4.1.10)
Diffstat (limited to 'src/charon')
-rw-r--r--src/charon/Makefile.am90
-rw-r--r--src/charon/Makefile.in373
-rw-r--r--src/charon/bus/bus.c306
-rw-r--r--src/charon/bus/bus.h52
-rw-r--r--src/charon/config/backends/sqlite_backend.c19
-rw-r--r--src/charon/config/credentials/local_credential_store.c4
-rw-r--r--src/charon/config/peer_cfg.c104
-rw-r--r--src/charon/config/peer_cfg.h53
-rw-r--r--src/charon/control/interface_manager.c656
-rwxr-xr-xsrc/charon/control/interfaces/stroke_interface.c61
-rw-r--r--src/charon/control/interfaces/xml_interface.c273
-rw-r--r--src/charon/daemon.c2
-rw-r--r--src/charon/encoding/payloads/configuration_attribute.c2
-rw-r--r--src/charon/encoding/payloads/eap_payload.c19
-rw-r--r--src/charon/encoding/payloads/eap_payload.h5
-rw-r--r--src/charon/encoding/payloads/endpoint_notify.c29
-rw-r--r--src/charon/encoding/payloads/endpoint_notify.h17
-rw-r--r--src/charon/encoding/payloads/ike_header.c3
-rw-r--r--src/charon/encoding/payloads/notify_payload.c26
-rw-r--r--src/charon/encoding/payloads/notify_payload.h5
-rw-r--r--src/charon/network/socket-raw.c771
-rw-r--r--src/charon/network/socket.c455
-rw-r--r--src/charon/network/socket.h4
-rw-r--r--src/charon/processing/jobs/callback_job.c14
-rw-r--r--src/charon/processing/jobs/initiate_mediation_job.c32
-rw-r--r--src/charon/processing/jobs/mediation_job.c6
-rw-r--r--src/charon/processing/jobs/process_message_job.c7
-rw-r--r--src/charon/processing/scheduler.c8
-rw-r--r--src/charon/sa/authenticators/eap/eap_aka.c1440
-rw-r--r--src/charon/sa/authenticators/eap/eap_aka.h141
-rw-r--r--src/charon/sa/authenticators/eap/eap_md5.c282
-rw-r--r--src/charon/sa/authenticators/eap/eap_md5.h59
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.c42
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.h11
-rw-r--r--src/charon/sa/authenticators/eap/eap_sim.c8
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.c105
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.h9
-rw-r--r--src/charon/sa/child_sa.c2
-rw-r--r--src/charon/sa/connect_manager.c77
-rw-r--r--src/charon/sa/ike_sa.c217
-rw-r--r--src/charon/sa/ike_sa.h45
-rw-r--r--src/charon/sa/mediation_manager.c4
-rw-r--r--src/charon/sa/task_manager.c16
-rw-r--r--src/charon/sa/tasks/ike_auth.c16
-rw-r--r--src/charon/sa/tasks/ike_auth_lifetime.c200
-rw-r--r--src/charon/sa/tasks/ike_auth_lifetime.h61
-rw-r--r--src/charon/sa/tasks/ike_mobike.c8
-rw-r--r--src/charon/sa/tasks/ike_p2p.c97
-rw-r--r--src/charon/sa/tasks/task.c1
-rw-r--r--src/charon/sa/tasks/task.h2
50 files changed, 4781 insertions, 1458 deletions
diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am
index 0d783cbbb..9111191b6 100644
--- a/src/charon/Makefile.am
+++ b/src/charon/Makefile.am
@@ -45,7 +45,7 @@ kernel/kernel_interface.c kernel/kernel_interface.h \
network/packet.c network/packet.h \
network/receiver.c network/receiver.h \
network/sender.c network/sender.h \
-network/socket.c network/socket.h \
+network/socket.h \
processing/jobs/job.h \
processing/jobs/acquire_job.c processing/jobs/acquire_job.h \
processing/jobs/callback_job.c processing/jobs/callback_job.h \
@@ -83,8 +83,16 @@ sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \
sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \
+sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \
sa/tasks/task.c sa/tasks/task.h
+# Use RAW socket if pluto gets built
+if USE_PLUTO
+ charon_SOURCES += network/socket-raw.c
+else
+ charon_SOURCES += network/socket.c
+endif
+
if USE_P2P
charon_SOURCES += encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \
processing/jobs/initiate_mediation_job.c processing/jobs/initiate_mediation_job.h \
@@ -104,56 +112,74 @@ if USE_LIBCURL
endif
-# build EAP plugins, EAP-Identity is always built
-#################################################
+# build EAP plugins
+###################
eap_LTLIBRARIES =
-eap_LTLIBRARIES += libeapidentity.la
-libeapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c
-libeapidentity_la_LDFLAGS = -module
+if USE_EAP_IDENTITY
+ eap_LTLIBRARIES += libcharon-eapidentity.la
+ libcharon_eapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c
+ libcharon_eapidentity_la_LDFLAGS = -module
+endif
+
+if USE_EAP_SIM
+ eap_LTLIBRARIES += libcharon-eapsim.la
+ libcharon_eapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c
+ libcharon_eapsim_la_LDFLAGS = -module
+endif
-if BUILD_EAP_SIM
- eap_LTLIBRARIES += libeapsim.la
- libeapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c
- libeapsim_la_LDFLAGS = -module
+if USE_EAP_MD5
+ eap_LTLIBRARIES += libcharon-eapmd5.la
+ libcharon_eapmd5_la_SOURCES = sa/authenticators/eap/eap_md5.h sa/authenticators/eap/eap_md5.c
+ libcharon_eapmd5_la_LDFLAGS = -module
endif
-# build backends, local backend is always built
-###############################################
+if USE_EAP_AKA
+ eap_LTLIBRARIES += libcharon-eapaka.la
+ libcharon_eapaka_la_SOURCES = sa/authenticators/eap/eap_aka.h sa/authenticators/eap/eap_aka.c
+ libcharon_eapaka_la_LDFLAGS = -module
+endif
+
+# build backends
+################
backend_LTLIBRARIES =
-backend_LTLIBRARIES += liblocal.la
-liblocal_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c
-liblocal_la_LDFLAGS = -module
+if USE_STROKE
+ backend_LTLIBRARIES += libcharon-local.la
+ libcharon_local_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c
+ libcharon_local_la_LDFLAGS = -module
+endif
if USE_LIBSQLITE
- backend_LTLIBRARIES += libsqlite.la
- libsqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c
- libsqlite_la_LIBADD = -lsqlite3
- libsqlite_la_LDFLAGS = -module
+ backend_LTLIBRARIES += libcharon-sqlite.la
+ libcharon_sqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c
+ libcharon_sqlite_la_LIBADD = -lsqlite3
+ libcharon_sqlite_la_LDFLAGS = -module
endif
-# build control interfaces, stroke interface is always built
-############################################################
+# build control interfaces
+##########################
interface_LTLIBRARIES =
-interface_LTLIBRARIES += libstroke.la
-libstroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c
-libstroke_la_LDFLAGS = -module
+if USE_STROKE
+ interface_LTLIBRARIES += libcharon-stroke.la
+ libcharon_stroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c
+ libcharon_stroke_la_LDFLAGS = -module
+endif
if USE_LIBDBUS
- interface_LTLIBRARIES += libdbus.la
- libdbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c
- libdbus_la_LDFLAGS = -module
- libdbus_la_LIBADD = ${dbus_LIBS}
+ interface_LTLIBRARIES += libcharon-dbus.la
+ libcharon_dbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c
+ libcharon_dbus_la_LDFLAGS = -module
+ libcharon_dbus_la_LIBADD = ${dbus_LIBS}
INCLUDES += ${dbus_CFLAGS}
endif
if USE_LIBXML
- interface_LTLIBRARIES += libxml.la
- libxml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c
- libxml_la_LDFLAGS = -module
- libxml_la_LIBADD = ${xml_LIBS}
+ interface_LTLIBRARIES += libcharon-xml.la
+ libcharon_xml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c
+ libcharon_xml_la_LDFLAGS = -module
+ libcharon_xml_la_LIBADD = ${xml_LIBS}
INCLUDES += ${xml_CFLAGS}
endif
diff --git a/src/charon/Makefile.in b/src/charon/Makefile.in
index e3b397f4e..bbae1270a 100644
--- a/src/charon/Makefile.in
+++ b/src/charon/Makefile.in
@@ -34,20 +34,29 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
ipsec_PROGRAMS = charon$(EXEEXT)
-@USE_P2P_TRUE@am__append_1 = encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \
+
+# Use RAW socket if pluto gets built
+@USE_PLUTO_TRUE@am__append_1 = network/socket-raw.c
+@USE_PLUTO_FALSE@am__append_2 = network/socket.c
+@USE_P2P_TRUE@am__append_3 = encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \
@USE_P2P_TRUE@ processing/jobs/initiate_mediation_job.c processing/jobs/initiate_mediation_job.h \
@USE_P2P_TRUE@ processing/jobs/mediation_job.c processing/jobs/mediation_job.h \
@USE_P2P_TRUE@ sa/connect_manager.c sa/connect_manager.h \
@USE_P2P_TRUE@ sa/mediation_manager.c sa/mediation_manager.h \
@USE_P2P_TRUE@ sa/tasks/ike_p2p.c sa/tasks/ike_p2p.h
-@USE_LIBCURL_TRUE@am__append_2 = -lcurl
-@BUILD_EAP_SIM_TRUE@am__append_3 = libeapsim.la
-@USE_LIBSQLITE_TRUE@am__append_4 = libsqlite.la
-@USE_LIBDBUS_TRUE@am__append_5 = libdbus.la
-@USE_LIBDBUS_TRUE@am__append_6 = ${dbus_CFLAGS}
-@USE_LIBXML_TRUE@am__append_7 = libxml.la
-@USE_LIBXML_TRUE@am__append_8 = ${xml_CFLAGS}
+@USE_LIBCURL_TRUE@am__append_4 = -lcurl
+@USE_EAP_IDENTITY_TRUE@am__append_5 = libcharon-eapidentity.la
+@USE_EAP_SIM_TRUE@am__append_6 = libcharon-eapsim.la
+@USE_EAP_MD5_TRUE@am__append_7 = libcharon-eapmd5.la
+@USE_EAP_AKA_TRUE@am__append_8 = libcharon-eapaka.la
+@USE_STROKE_TRUE@am__append_9 = libcharon-local.la
+@USE_LIBSQLITE_TRUE@am__append_10 = libcharon-sqlite.la
+@USE_STROKE_TRUE@am__append_11 = libcharon-stroke.la
+@USE_LIBDBUS_TRUE@am__append_12 = libcharon-dbus.la
+@USE_LIBDBUS_TRUE@am__append_13 = ${dbus_CFLAGS}
+@USE_LIBXML_TRUE@am__append_14 = libcharon-xml.la
+@USE_LIBXML_TRUE@am__append_15 = ${xml_CFLAGS}
subdir = src/charon
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -70,60 +79,102 @@ interfaceLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(backend_LTLIBRARIES) $(eap_LTLIBRARIES) \
$(interface_LTLIBRARIES)
am__DEPENDENCIES_1 =
-@USE_LIBDBUS_TRUE@libdbus_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
-am__libdbus_la_SOURCES_DIST = control/interfaces/dbus_interface.h \
+@USE_LIBDBUS_TRUE@libcharon_dbus_la_DEPENDENCIES = \
+@USE_LIBDBUS_TRUE@ $(am__DEPENDENCIES_1)
+am__libcharon_dbus_la_SOURCES_DIST = \
+ control/interfaces/dbus_interface.h \
control/interfaces/dbus_interface.c
-@USE_LIBDBUS_TRUE@am_libdbus_la_OBJECTS = dbus_interface.lo
-libdbus_la_OBJECTS = $(am_libdbus_la_OBJECTS)
-libdbus_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+@USE_LIBDBUS_TRUE@am_libcharon_dbus_la_OBJECTS = dbus_interface.lo
+libcharon_dbus_la_OBJECTS = $(am_libcharon_dbus_la_OBJECTS)
+libcharon_dbus_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libcharon_dbus_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_LIBDBUS_TRUE@am_libcharon_dbus_la_rpath = -rpath $(interfacedir)
+libcharon_eapaka_la_LIBADD =
+am__libcharon_eapaka_la_SOURCES_DIST = \
+ sa/authenticators/eap/eap_aka.h \
+ sa/authenticators/eap/eap_aka.c
+@USE_EAP_AKA_TRUE@am_libcharon_eapaka_la_OBJECTS = eap_aka.lo
+libcharon_eapaka_la_OBJECTS = $(am_libcharon_eapaka_la_OBJECTS)
+libcharon_eapaka_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libcharon_eapaka_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_EAP_AKA_TRUE@am_libcharon_eapaka_la_rpath = -rpath $(eapdir)
+libcharon_eapidentity_la_LIBADD =
+am__libcharon_eapidentity_la_SOURCES_DIST = \
+ sa/authenticators/eap/eap_identity.h \
+ sa/authenticators/eap/eap_identity.c
+@USE_EAP_IDENTITY_TRUE@am_libcharon_eapidentity_la_OBJECTS = \
+@USE_EAP_IDENTITY_TRUE@ eap_identity.lo
+libcharon_eapidentity_la_OBJECTS = \
+ $(am_libcharon_eapidentity_la_OBJECTS)
+libcharon_eapidentity_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libdbus_la_LDFLAGS) $(LDFLAGS) -o $@
-@USE_LIBDBUS_TRUE@am_libdbus_la_rpath = -rpath $(interfacedir)
-libeapidentity_la_LIBADD =
-am_libeapidentity_la_OBJECTS = eap_identity.lo
-libeapidentity_la_OBJECTS = $(am_libeapidentity_la_OBJECTS)
-libeapidentity_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(libcharon_eapidentity_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_EAP_IDENTITY_TRUE@am_libcharon_eapidentity_la_rpath = -rpath \
+@USE_EAP_IDENTITY_TRUE@ $(eapdir)
+libcharon_eapmd5_la_LIBADD =
+am__libcharon_eapmd5_la_SOURCES_DIST = \
+ sa/authenticators/eap/eap_md5.h \
+ sa/authenticators/eap/eap_md5.c
+@USE_EAP_MD5_TRUE@am_libcharon_eapmd5_la_OBJECTS = eap_md5.lo
+libcharon_eapmd5_la_OBJECTS = $(am_libcharon_eapmd5_la_OBJECTS)
+libcharon_eapmd5_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libeapidentity_la_LDFLAGS) $(LDFLAGS) -o $@
-libeapsim_la_LIBADD =
-am__libeapsim_la_SOURCES_DIST = sa/authenticators/eap/eap_sim.h \
+ $(libcharon_eapmd5_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_EAP_MD5_TRUE@am_libcharon_eapmd5_la_rpath = -rpath $(eapdir)
+libcharon_eapsim_la_LIBADD =
+am__libcharon_eapsim_la_SOURCES_DIST = \
+ sa/authenticators/eap/eap_sim.h \
sa/authenticators/eap/eap_sim.c
-@BUILD_EAP_SIM_TRUE@am_libeapsim_la_OBJECTS = eap_sim.lo
-libeapsim_la_OBJECTS = $(am_libeapsim_la_OBJECTS)
-libeapsim_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+@USE_EAP_SIM_TRUE@am_libcharon_eapsim_la_OBJECTS = eap_sim.lo
+libcharon_eapsim_la_OBJECTS = $(am_libcharon_eapsim_la_OBJECTS)
+libcharon_eapsim_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libeapsim_la_LDFLAGS) $(LDFLAGS) -o $@
-@BUILD_EAP_SIM_TRUE@am_libeapsim_la_rpath = -rpath $(eapdir)
-liblocal_la_LIBADD =
-am_liblocal_la_OBJECTS = local_backend.lo
-liblocal_la_OBJECTS = $(am_liblocal_la_OBJECTS)
-liblocal_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(libcharon_eapsim_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_EAP_SIM_TRUE@am_libcharon_eapsim_la_rpath = -rpath $(eapdir)
+libcharon_local_la_LIBADD =
+am__libcharon_local_la_SOURCES_DIST = config/backends/local_backend.h \
+ config/backends/local_backend.c
+@USE_STROKE_TRUE@am_libcharon_local_la_OBJECTS = local_backend.lo
+libcharon_local_la_OBJECTS = $(am_libcharon_local_la_OBJECTS)
+libcharon_local_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(liblocal_la_LDFLAGS) $(LDFLAGS) -o $@
-libsqlite_la_DEPENDENCIES =
-am__libsqlite_la_SOURCES_DIST = config/backends/sqlite_backend.h \
+ $(libcharon_local_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_STROKE_TRUE@am_libcharon_local_la_rpath = -rpath $(backenddir)
+libcharon_sqlite_la_DEPENDENCIES =
+am__libcharon_sqlite_la_SOURCES_DIST = \
+ config/backends/sqlite_backend.h \
config/backends/sqlite_backend.c
-@USE_LIBSQLITE_TRUE@am_libsqlite_la_OBJECTS = sqlite_backend.lo
-libsqlite_la_OBJECTS = $(am_libsqlite_la_OBJECTS)
-libsqlite_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+@USE_LIBSQLITE_TRUE@am_libcharon_sqlite_la_OBJECTS = \
+@USE_LIBSQLITE_TRUE@ sqlite_backend.lo
+libcharon_sqlite_la_OBJECTS = $(am_libcharon_sqlite_la_OBJECTS)
+libcharon_sqlite_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libsqlite_la_LDFLAGS) $(LDFLAGS) -o $@
-@USE_LIBSQLITE_TRUE@am_libsqlite_la_rpath = -rpath $(backenddir)
-libstroke_la_LIBADD =
-am_libstroke_la_OBJECTS = stroke_interface.lo
-libstroke_la_OBJECTS = $(am_libstroke_la_OBJECTS)
-libstroke_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(libcharon_sqlite_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_LIBSQLITE_TRUE@am_libcharon_sqlite_la_rpath = -rpath \
+@USE_LIBSQLITE_TRUE@ $(backenddir)
+libcharon_stroke_la_LIBADD =
+am__libcharon_stroke_la_SOURCES_DIST = \
+ control/interfaces/stroke_interface.h \
+ control/interfaces/stroke_interface.c
+@USE_STROKE_TRUE@am_libcharon_stroke_la_OBJECTS = stroke_interface.lo
+libcharon_stroke_la_OBJECTS = $(am_libcharon_stroke_la_OBJECTS)
+libcharon_stroke_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libstroke_la_LDFLAGS) $(LDFLAGS) -o $@
-@USE_LIBXML_TRUE@libxml_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
-am__libxml_la_SOURCES_DIST = control/interfaces/xml_interface.h \
+ $(libcharon_stroke_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_STROKE_TRUE@am_libcharon_stroke_la_rpath = -rpath $(interfacedir)
+@USE_LIBXML_TRUE@libcharon_xml_la_DEPENDENCIES = \
+@USE_LIBXML_TRUE@ $(am__DEPENDENCIES_1)
+am__libcharon_xml_la_SOURCES_DIST = \
+ control/interfaces/xml_interface.h \
control/interfaces/xml_interface.c
-@USE_LIBXML_TRUE@am_libxml_la_OBJECTS = xml_interface.lo
-libxml_la_OBJECTS = $(am_libxml_la_OBJECTS)
-libxml_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+@USE_LIBXML_TRUE@am_libcharon_xml_la_OBJECTS = xml_interface.lo
+libcharon_xml_la_OBJECTS = $(am_libcharon_xml_la_OBJECTS)
+libcharon_xml_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libxml_la_LDFLAGS) $(LDFLAGS) -o $@
-@USE_LIBXML_TRUE@am_libxml_la_rpath = -rpath $(interfacedir)
+ $(libcharon_xml_la_LDFLAGS) $(LDFLAGS) -o $@
+@USE_LIBXML_TRUE@am_libcharon_xml_la_rpath = -rpath $(interfacedir)
ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(ipsec_PROGRAMS)
am__charon_SOURCES_DIST = bus/bus.c bus/bus.h \
@@ -181,7 +232,7 @@ am__charon_SOURCES_DIST = bus/bus.c bus/bus.h \
kernel/kernel_interface.c kernel/kernel_interface.h \
network/packet.c network/packet.h network/receiver.c \
network/receiver.h network/sender.c network/sender.h \
- network/socket.c network/socket.h processing/jobs/job.h \
+ network/socket.h processing/jobs/job.h \
processing/jobs/acquire_job.c processing/jobs/acquire_job.h \
processing/jobs/callback_job.c processing/jobs/callback_job.h \
processing/jobs/delete_child_sa_job.c \
@@ -225,7 +276,9 @@ am__charon_SOURCES_DIST = bus/bus.c bus/bus.h \
sa/tasks/ike_natd.h sa/tasks/ike_mobike.c \
sa/tasks/ike_mobike.h sa/tasks/ike_rekey.c \
sa/tasks/ike_rekey.h sa/tasks/ike_reauth.c \
- sa/tasks/ike_reauth.h sa/tasks/task.c sa/tasks/task.h \
+ sa/tasks/ike_reauth.h sa/tasks/ike_auth_lifetime.c \
+ sa/tasks/ike_auth_lifetime.h sa/tasks/task.c sa/tasks/task.h \
+ network/socket-raw.c network/socket.c \
encoding/payloads/endpoint_notify.c \
encoding/payloads/endpoint_notify.h \
processing/jobs/initiate_mediation_job.c \
@@ -234,7 +287,9 @@ am__charon_SOURCES_DIST = bus/bus.c bus/bus.h \
processing/jobs/mediation_job.h sa/connect_manager.c \
sa/connect_manager.h sa/mediation_manager.c \
sa/mediation_manager.h sa/tasks/ike_p2p.c sa/tasks/ike_p2p.h
-@USE_P2P_TRUE@am__objects_1 = endpoint_notify.$(OBJEXT) \
+@USE_PLUTO_TRUE@am__objects_1 = socket-raw.$(OBJEXT)
+@USE_PLUTO_FALSE@am__objects_2 = socket.$(OBJEXT)
+@USE_P2P_TRUE@am__objects_3 = endpoint_notify.$(OBJEXT) \
@USE_P2P_TRUE@ initiate_mediation_job.$(OBJEXT) \
@USE_P2P_TRUE@ mediation_job.$(OBJEXT) \
@USE_P2P_TRUE@ connect_manager.$(OBJEXT) \
@@ -258,7 +313,7 @@ am_charon_OBJECTS = bus.$(OBJEXT) file_logger.$(OBJEXT) \
ts_payload.$(OBJEXT) unknown_payload.$(OBJEXT) \
vendor_id_payload.$(OBJEXT) kernel_interface.$(OBJEXT) \
packet.$(OBJEXT) receiver.$(OBJEXT) sender.$(OBJEXT) \
- socket.$(OBJEXT) acquire_job.$(OBJEXT) callback_job.$(OBJEXT) \
+ acquire_job.$(OBJEXT) callback_job.$(OBJEXT) \
delete_child_sa_job.$(OBJEXT) delete_ike_sa_job.$(OBJEXT) \
process_message_job.$(OBJEXT) rekey_child_sa_job.$(OBJEXT) \
rekey_ike_sa_job.$(OBJEXT) retransmit_job.$(OBJEXT) \
@@ -273,7 +328,9 @@ am_charon_OBJECTS = bus.$(OBJEXT) file_logger.$(OBJEXT) \
ike_auth.$(OBJEXT) ike_cert.$(OBJEXT) ike_config.$(OBJEXT) \
ike_delete.$(OBJEXT) ike_dpd.$(OBJEXT) ike_init.$(OBJEXT) \
ike_natd.$(OBJEXT) ike_mobike.$(OBJEXT) ike_rekey.$(OBJEXT) \
- ike_reauth.$(OBJEXT) task.$(OBJEXT) $(am__objects_1)
+ ike_reauth.$(OBJEXT) ike_auth_lifetime.$(OBJEXT) \
+ task.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
+ $(am__objects_3)
charon_OBJECTS = $(am_charon_OBJECTS)
charon_DEPENDENCIES = \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
@@ -290,14 +347,21 @@ CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
-SOURCES = $(libdbus_la_SOURCES) $(libeapidentity_la_SOURCES) \
- $(libeapsim_la_SOURCES) $(liblocal_la_SOURCES) \
- $(libsqlite_la_SOURCES) $(libstroke_la_SOURCES) \
- $(libxml_la_SOURCES) $(charon_SOURCES)
-DIST_SOURCES = $(am__libdbus_la_SOURCES_DIST) \
- $(libeapidentity_la_SOURCES) $(am__libeapsim_la_SOURCES_DIST) \
- $(liblocal_la_SOURCES) $(am__libsqlite_la_SOURCES_DIST) \
- $(libstroke_la_SOURCES) $(am__libxml_la_SOURCES_DIST) \
+SOURCES = $(libcharon_dbus_la_SOURCES) $(libcharon_eapaka_la_SOURCES) \
+ $(libcharon_eapidentity_la_SOURCES) \
+ $(libcharon_eapmd5_la_SOURCES) $(libcharon_eapsim_la_SOURCES) \
+ $(libcharon_local_la_SOURCES) $(libcharon_sqlite_la_SOURCES) \
+ $(libcharon_stroke_la_SOURCES) $(libcharon_xml_la_SOURCES) \
+ $(charon_SOURCES)
+DIST_SOURCES = $(am__libcharon_dbus_la_SOURCES_DIST) \
+ $(am__libcharon_eapaka_la_SOURCES_DIST) \
+ $(am__libcharon_eapidentity_la_SOURCES_DIST) \
+ $(am__libcharon_eapmd5_la_SOURCES_DIST) \
+ $(am__libcharon_eapsim_la_SOURCES_DIST) \
+ $(am__libcharon_local_la_SOURCES_DIST) \
+ $(am__libcharon_sqlite_la_SOURCES_DIST) \
+ $(am__libcharon_stroke_la_SOURCES_DIST) \
+ $(am__libcharon_xml_la_SOURCES_DIST) \
$(am__charon_SOURCES_DIST)
ETAGS = etags
CTAGS = ctags
@@ -486,7 +550,7 @@ charon_SOURCES = bus/bus.c bus/bus.h bus/listeners/file_logger.c \
kernel/kernel_interface.c kernel/kernel_interface.h \
network/packet.c network/packet.h network/receiver.c \
network/receiver.h network/sender.c network/sender.h \
- network/socket.c network/socket.h processing/jobs/job.h \
+ network/socket.h processing/jobs/job.h \
processing/jobs/acquire_job.c processing/jobs/acquire_job.h \
processing/jobs/callback_job.c processing/jobs/callback_job.h \
processing/jobs/delete_child_sa_job.c \
@@ -530,45 +594,52 @@ charon_SOURCES = bus/bus.c bus/bus.h bus/listeners/file_logger.c \
sa/tasks/ike_natd.h sa/tasks/ike_mobike.c \
sa/tasks/ike_mobike.h sa/tasks/ike_rekey.c \
sa/tasks/ike_rekey.h sa/tasks/ike_reauth.c \
- sa/tasks/ike_reauth.h sa/tasks/task.c sa/tasks/task.h \
- $(am__append_1)
+ sa/tasks/ike_reauth.h sa/tasks/ike_auth_lifetime.c \
+ sa/tasks/ike_auth_lifetime.h sa/tasks/task.c sa/tasks/task.h \
+ $(am__append_1) $(am__append_2) $(am__append_3)
INCLUDES = -I${linuxdir} -I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke \
- $(am__append_6) $(am__append_8)
+ $(am__append_13) $(am__append_15)
AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_PIDDIR=\"${piddir}\" \
-DIPSEC_EAPDIR=\"${eapdir}\" -DIPSEC_BACKENDDIR=\"${backenddir}\" -DIPSEC_INTERFACEDIR=\"${interfacedir}\"
charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \
- -lgmp -lpthread -lm -ldl $(am__append_2)
-
-# build EAP plugins, EAP-Identity is always built
-#################################################
-eap_LTLIBRARIES = libeapidentity.la $(am__append_3)
-libeapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c
-libeapidentity_la_LDFLAGS = -module
-@BUILD_EAP_SIM_TRUE@libeapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c
-@BUILD_EAP_SIM_TRUE@libeapsim_la_LDFLAGS = -module
-
-# build backends, local backend is always built
-###############################################
-backend_LTLIBRARIES = liblocal.la $(am__append_4)
-liblocal_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c
-liblocal_la_LDFLAGS = -module
-@USE_LIBSQLITE_TRUE@libsqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c
-@USE_LIBSQLITE_TRUE@libsqlite_la_LIBADD = -lsqlite3
-@USE_LIBSQLITE_TRUE@libsqlite_la_LDFLAGS = -module
-
-# build control interfaces, stroke interface is always built
-############################################################
-interface_LTLIBRARIES = libstroke.la $(am__append_5) $(am__append_7)
-libstroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c
-libstroke_la_LDFLAGS = -module
-@USE_LIBDBUS_TRUE@libdbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c
-@USE_LIBDBUS_TRUE@libdbus_la_LDFLAGS = -module
-@USE_LIBDBUS_TRUE@libdbus_la_LIBADD = ${dbus_LIBS}
-@USE_LIBXML_TRUE@libxml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c
-@USE_LIBXML_TRUE@libxml_la_LDFLAGS = -module
-@USE_LIBXML_TRUE@libxml_la_LIBADD = ${xml_LIBS}
+ -lgmp -lpthread -lm -ldl $(am__append_4)
+
+# build EAP plugins
+###################
+eap_LTLIBRARIES = $(am__append_5) $(am__append_6) $(am__append_7) \
+ $(am__append_8)
+@USE_EAP_IDENTITY_TRUE@libcharon_eapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c
+@USE_EAP_IDENTITY_TRUE@libcharon_eapidentity_la_LDFLAGS = -module
+@USE_EAP_SIM_TRUE@libcharon_eapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c
+@USE_EAP_SIM_TRUE@libcharon_eapsim_la_LDFLAGS = -module
+@USE_EAP_MD5_TRUE@libcharon_eapmd5_la_SOURCES = sa/authenticators/eap/eap_md5.h sa/authenticators/eap/eap_md5.c
+@USE_EAP_MD5_TRUE@libcharon_eapmd5_la_LDFLAGS = -module
+@USE_EAP_AKA_TRUE@libcharon_eapaka_la_SOURCES = sa/authenticators/eap/eap_aka.h sa/authenticators/eap/eap_aka.c
+@USE_EAP_AKA_TRUE@libcharon_eapaka_la_LDFLAGS = -module
+
+# build backends
+################
+backend_LTLIBRARIES = $(am__append_9) $(am__append_10)
+@USE_STROKE_TRUE@libcharon_local_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c
+@USE_STROKE_TRUE@libcharon_local_la_LDFLAGS = -module
+@USE_LIBSQLITE_TRUE@libcharon_sqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c
+@USE_LIBSQLITE_TRUE@libcharon_sqlite_la_LIBADD = -lsqlite3
+@USE_LIBSQLITE_TRUE@libcharon_sqlite_la_LDFLAGS = -module
+
+# build control interfaces
+##########################
+interface_LTLIBRARIES = $(am__append_11) $(am__append_12) \
+ $(am__append_14)
+@USE_STROKE_TRUE@libcharon_stroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c
+@USE_STROKE_TRUE@libcharon_stroke_la_LDFLAGS = -module
+@USE_LIBDBUS_TRUE@libcharon_dbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c
+@USE_LIBDBUS_TRUE@libcharon_dbus_la_LDFLAGS = -module
+@USE_LIBDBUS_TRUE@libcharon_dbus_la_LIBADD = ${dbus_LIBS}
+@USE_LIBXML_TRUE@libcharon_xml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c
+@USE_LIBXML_TRUE@libcharon_xml_la_LDFLAGS = -module
+@USE_LIBXML_TRUE@libcharon_xml_la_LIBADD = ${xml_LIBS}
all: all-am
.SUFFIXES:
@@ -683,20 +754,24 @@ clean-interfaceLTLIBRARIES:
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
-libdbus.la: $(libdbus_la_OBJECTS) $(libdbus_la_DEPENDENCIES)
- $(libdbus_la_LINK) $(am_libdbus_la_rpath) $(libdbus_la_OBJECTS) $(libdbus_la_LIBADD) $(LIBS)
-libeapidentity.la: $(libeapidentity_la_OBJECTS) $(libeapidentity_la_DEPENDENCIES)
- $(libeapidentity_la_LINK) -rpath $(eapdir) $(libeapidentity_la_OBJECTS) $(libeapidentity_la_LIBADD) $(LIBS)
-libeapsim.la: $(libeapsim_la_OBJECTS) $(libeapsim_la_DEPENDENCIES)
- $(libeapsim_la_LINK) $(am_libeapsim_la_rpath) $(libeapsim_la_OBJECTS) $(libeapsim_la_LIBADD) $(LIBS)
-liblocal.la: $(liblocal_la_OBJECTS) $(liblocal_la_DEPENDENCIES)
- $(liblocal_la_LINK) -rpath $(backenddir) $(liblocal_la_OBJECTS) $(liblocal_la_LIBADD) $(LIBS)
-libsqlite.la: $(libsqlite_la_OBJECTS) $(libsqlite_la_DEPENDENCIES)
- $(libsqlite_la_LINK) $(am_libsqlite_la_rpath) $(libsqlite_la_OBJECTS) $(libsqlite_la_LIBADD) $(LIBS)
-libstroke.la: $(libstroke_la_OBJECTS) $(libstroke_la_DEPENDENCIES)
- $(libstroke_la_LINK) -rpath $(interfacedir) $(libstroke_la_OBJECTS) $(libstroke_la_LIBADD) $(LIBS)
-libxml.la: $(libxml_la_OBJECTS) $(libxml_la_DEPENDENCIES)
- $(libxml_la_LINK) $(am_libxml_la_rpath) $(libxml_la_OBJECTS) $(libxml_la_LIBADD) $(LIBS)
+libcharon-dbus.la: $(libcharon_dbus_la_OBJECTS) $(libcharon_dbus_la_DEPENDENCIES)
+ $(libcharon_dbus_la_LINK) $(am_libcharon_dbus_la_rpath) $(libcharon_dbus_la_OBJECTS) $(libcharon_dbus_la_LIBADD) $(LIBS)
+libcharon-eapaka.la: $(libcharon_eapaka_la_OBJECTS) $(libcharon_eapaka_la_DEPENDENCIES)
+ $(libcharon_eapaka_la_LINK) $(am_libcharon_eapaka_la_rpath) $(libcharon_eapaka_la_OBJECTS) $(libcharon_eapaka_la_LIBADD) $(LIBS)
+libcharon-eapidentity.la: $(libcharon_eapidentity_la_OBJECTS) $(libcharon_eapidentity_la_DEPENDENCIES)
+ $(libcharon_eapidentity_la_LINK) $(am_libcharon_eapidentity_la_rpath) $(libcharon_eapidentity_la_OBJECTS) $(libcharon_eapidentity_la_LIBADD) $(LIBS)
+libcharon-eapmd5.la: $(libcharon_eapmd5_la_OBJECTS) $(libcharon_eapmd5_la_DEPENDENCIES)
+ $(libcharon_eapmd5_la_LINK) $(am_libcharon_eapmd5_la_rpath) $(libcharon_eapmd5_la_OBJECTS) $(libcharon_eapmd5_la_LIBADD) $(LIBS)
+libcharon-eapsim.la: $(libcharon_eapsim_la_OBJECTS) $(libcharon_eapsim_la_DEPENDENCIES)
+ $(libcharon_eapsim_la_LINK) $(am_libcharon_eapsim_la_rpath) $(libcharon_eapsim_la_OBJECTS) $(libcharon_eapsim_la_LIBADD) $(LIBS)
+libcharon-local.la: $(libcharon_local_la_OBJECTS) $(libcharon_local_la_DEPENDENCIES)
+ $(libcharon_local_la_LINK) $(am_libcharon_local_la_rpath) $(libcharon_local_la_OBJECTS) $(libcharon_local_la_LIBADD) $(LIBS)
+libcharon-sqlite.la: $(libcharon_sqlite_la_OBJECTS) $(libcharon_sqlite_la_DEPENDENCIES)
+ $(libcharon_sqlite_la_LINK) $(am_libcharon_sqlite_la_rpath) $(libcharon_sqlite_la_OBJECTS) $(libcharon_sqlite_la_LIBADD) $(LIBS)
+libcharon-stroke.la: $(libcharon_stroke_la_OBJECTS) $(libcharon_stroke_la_DEPENDENCIES)
+ $(libcharon_stroke_la_LINK) $(am_libcharon_stroke_la_rpath) $(libcharon_stroke_la_OBJECTS) $(libcharon_stroke_la_LIBADD) $(LIBS)
+libcharon-xml.la: $(libcharon_xml_la_OBJECTS) $(libcharon_xml_la_DEPENDENCIES)
+ $(libcharon_xml_la_LINK) $(am_libcharon_xml_la_rpath) $(libcharon_xml_la_OBJECTS) $(libcharon_xml_la_LIBADD) $(LIBS)
install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)"
@@ -756,8 +831,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_child_sa_job.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_ike_sa_job.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_aka.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_authenticator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_identity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_md5.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_method.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_payload.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_sim.Plo@am__quote@
@@ -768,6 +845,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_payload.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_auth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_auth_lifetime.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_cert.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_cfg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_config.Po@am__quote@
@@ -814,6 +892,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send_dpd_job.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send_keepalive_job.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sender.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket-raw.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlite_backend.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_interface.Plo@am__quote@
@@ -857,6 +936,13 @@ dbus_interface.lo: control/interfaces/dbus_interface.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 dbus_interface.lo `test -f 'control/interfaces/dbus_interface.c' || echo '$(srcdir)/'`control/interfaces/dbus_interface.c
+eap_aka.lo: sa/authenticators/eap/eap_aka.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_aka.lo -MD -MP -MF $(DEPDIR)/eap_aka.Tpo -c -o eap_aka.lo `test -f 'sa/authenticators/eap/eap_aka.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_aka.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/eap_aka.Tpo $(DEPDIR)/eap_aka.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_aka.c' object='eap_aka.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 eap_aka.lo `test -f 'sa/authenticators/eap/eap_aka.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_aka.c
+
eap_identity.lo: sa/authenticators/eap/eap_identity.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_identity.lo -MD -MP -MF $(DEPDIR)/eap_identity.Tpo -c -o eap_identity.lo `test -f 'sa/authenticators/eap/eap_identity.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_identity.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/eap_identity.Tpo $(DEPDIR)/eap_identity.Plo
@@ -864,6 +950,13 @@ eap_identity.lo: sa/authenticators/eap/eap_identity.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 eap_identity.lo `test -f 'sa/authenticators/eap/eap_identity.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_identity.c
+eap_md5.lo: sa/authenticators/eap/eap_md5.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_md5.lo -MD -MP -MF $(DEPDIR)/eap_md5.Tpo -c -o eap_md5.lo `test -f 'sa/authenticators/eap/eap_md5.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_md5.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/eap_md5.Tpo $(DEPDIR)/eap_md5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_md5.c' object='eap_md5.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 eap_md5.lo `test -f 'sa/authenticators/eap/eap_md5.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_md5.c
+
eap_sim.lo: sa/authenticators/eap/eap_sim.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_sim.lo -MD -MP -MF $(DEPDIR)/eap_sim.Tpo -c -o eap_sim.lo `test -f 'sa/authenticators/eap/eap_sim.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_sim.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/eap_sim.Tpo $(DEPDIR)/eap_sim.Plo
@@ -1473,20 +1566,6 @@ sender.obj: network/sender.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sender.obj `if test -f 'network/sender.c'; then $(CYGPATH_W) 'network/sender.c'; else $(CYGPATH_W) '$(srcdir)/network/sender.c'; fi`
-socket.o: network/socket.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.o -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c
-
-socket.obj: network/socket.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.obj -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi`
-
acquire_job.o: processing/jobs/acquire_job.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acquire_job.o -MD -MP -MF $(DEPDIR)/acquire_job.Tpo -c -o acquire_job.o `test -f 'processing/jobs/acquire_job.c' || echo '$(srcdir)/'`processing/jobs/acquire_job.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/acquire_job.Tpo $(DEPDIR)/acquire_job.Po
@@ -1991,6 +2070,20 @@ ike_reauth.obj: sa/tasks/ike_reauth.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_reauth.obj `if test -f 'sa/tasks/ike_reauth.c'; then $(CYGPATH_W) 'sa/tasks/ike_reauth.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_reauth.c'; fi`
+ike_auth_lifetime.o: sa/tasks/ike_auth_lifetime.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth_lifetime.o -MD -MP -MF $(DEPDIR)/ike_auth_lifetime.Tpo -c -o ike_auth_lifetime.o `test -f 'sa/tasks/ike_auth_lifetime.c' || echo '$(srcdir)/'`sa/tasks/ike_auth_lifetime.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_auth_lifetime.Tpo $(DEPDIR)/ike_auth_lifetime.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_auth_lifetime.c' object='ike_auth_lifetime.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_auth_lifetime.o `test -f 'sa/tasks/ike_auth_lifetime.c' || echo '$(srcdir)/'`sa/tasks/ike_auth_lifetime.c
+
+ike_auth_lifetime.obj: sa/tasks/ike_auth_lifetime.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth_lifetime.obj -MD -MP -MF $(DEPDIR)/ike_auth_lifetime.Tpo -c -o ike_auth_lifetime.obj `if test -f 'sa/tasks/ike_auth_lifetime.c'; then $(CYGPATH_W) 'sa/tasks/ike_auth_lifetime.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_auth_lifetime.c'; fi`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_auth_lifetime.Tpo $(DEPDIR)/ike_auth_lifetime.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_auth_lifetime.c' object='ike_auth_lifetime.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_auth_lifetime.obj `if test -f 'sa/tasks/ike_auth_lifetime.c'; then $(CYGPATH_W) 'sa/tasks/ike_auth_lifetime.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_auth_lifetime.c'; fi`
+
task.o: sa/tasks/task.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task.o -MD -MP -MF $(DEPDIR)/task.Tpo -c -o task.o `test -f 'sa/tasks/task.c' || echo '$(srcdir)/'`sa/tasks/task.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/task.Tpo $(DEPDIR)/task.Po
@@ -2005,6 +2098,34 @@ task.obj: sa/tasks/task.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task.obj `if test -f 'sa/tasks/task.c'; then $(CYGPATH_W) 'sa/tasks/task.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/task.c'; fi`
+socket-raw.o: network/socket-raw.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket-raw.o -MD -MP -MF $(DEPDIR)/socket-raw.Tpo -c -o socket-raw.o `test -f 'network/socket-raw.c' || echo '$(srcdir)/'`network/socket-raw.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket-raw.Tpo $(DEPDIR)/socket-raw.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket-raw.c' object='socket-raw.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket-raw.o `test -f 'network/socket-raw.c' || echo '$(srcdir)/'`network/socket-raw.c
+
+socket-raw.obj: network/socket-raw.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket-raw.obj -MD -MP -MF $(DEPDIR)/socket-raw.Tpo -c -o socket-raw.obj `if test -f 'network/socket-raw.c'; then $(CYGPATH_W) 'network/socket-raw.c'; else $(CYGPATH_W) '$(srcdir)/network/socket-raw.c'; fi`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket-raw.Tpo $(DEPDIR)/socket-raw.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket-raw.c' object='socket-raw.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket-raw.obj `if test -f 'network/socket-raw.c'; then $(CYGPATH_W) 'network/socket-raw.c'; else $(CYGPATH_W) '$(srcdir)/network/socket-raw.c'; fi`
+
+socket.o: network/socket.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.o -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c
+
+socket.obj: network/socket.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.obj -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi`
+
endpoint_notify.o: encoding/payloads/endpoint_notify.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT endpoint_notify.o -MD -MP -MF $(DEPDIR)/endpoint_notify.Tpo -c -o endpoint_notify.o `test -f 'encoding/payloads/endpoint_notify.c' || echo '$(srcdir)/'`encoding/payloads/endpoint_notify.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/endpoint_notify.Tpo $(DEPDIR)/endpoint_notify.Po
diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c
index 5fda36925..e53ac43ce 100644
--- a/src/charon/bus/bus.c
+++ b/src/charon/bus/bus.c
@@ -24,6 +24,8 @@
#include <pthread.h>
+#include <daemon.h>
+
ENUM(signal_names, SIG_ANY, SIG_MAX,
/** should not get printed */
"SIG_ANY",
@@ -53,104 +55,74 @@ ENUM(signal_names, SIG_ANY, SIG_MAX,
"SIG_MAX",
);
-typedef struct active_listener_t active_listener_t;
+typedef struct private_bus_t private_bus_t;
/**
- * information for a active listener
+ * Private data of a bus_t object.
*/
-struct active_listener_t {
-
- /**
- * associated thread
- */
- pthread_t id;
-
- /**
- * condvar to wait for a signal
- */
- pthread_cond_t cond;
-
- /**
- * state of the thread
- */
- enum {
- /** not registered, do not wait for thread */
- UNREGISTERED,
- /** registered, if a signal occurs, wait until it is LISTENING */
- REGISTERED,
- /** listening, deliver signal */
- LISTENING,
- } state;
-
- /**
- * currently processed signals type
- */
- signal_t signal;
-
+struct private_bus_t {
/**
- * verbosity level of the signal
+ * Public part of a bus_t object.
*/
- level_t level;
+ bus_t public;
/**
- * current processed signals thread number
+ * List of registered listeners as entry_t's
*/
- int thread;
+ linked_list_t *listeners;
/**
- * currently processed signals ike_sa
+ * mutex to synchronize active listeners
*/
- ike_sa_t *ike_sa;
+ pthread_mutex_t mutex;
/**
- * currently processed signals format string
+ * Thread local storage for a unique, simple thread ID
*/
- char *format;
+ pthread_key_t thread_id;
/**
- * currently processed signals format varargs
+ * Thread local storage the threads IKE_SA
*/
- va_list args;
-
+ pthread_key_t thread_sa;
};
-typedef struct private_bus_t private_bus_t;
+typedef struct entry_t entry_t;
/**
- * Private data of a bus_t object.
+ * a listener entry, either active or passive
*/
-struct private_bus_t {
- /**
- * Public part of a bus_t object.
- */
- bus_t public;
-
- /**
- * List of registered listeners implementing the bus_t interface
- */
- linked_list_t *listeners;
-
+struct entry_t {
+
/**
- * List of active listeners with listener_state TRUE
+ * registered listener interface
*/
- linked_list_t *active_listeners;
+ bus_listener_t *listener;
/**
- * mutex to synchronize active listeners
+ * is this a active listen() call with a blocking thread
*/
- pthread_mutex_t mutex;
+ bool blocker;
/**
- * Thread local storage for a unique, simple thread ID
+ * condvar where active listeners wait
*/
- pthread_key_t thread_id;
+ pthread_cond_t cond;
+};
+
+/**
+ * create a listener entry
+ */
+static entry_t *entry_create(bus_listener_t *listener, bool blocker)
+{
+ entry_t *this = malloc_thing(entry_t);
- /**
- * Thread local storage the threads IKE_SA
- */
- pthread_key_t thread_sa;
+ this->listener = listener;
+ this->blocker = blocker;
+ pthread_cond_init(&this->cond, NULL);
-};
+ return this;
+}
/**
* Get a unique thread number for a calling thread. Since
@@ -160,7 +132,7 @@ struct private_bus_t {
static int get_thread_number(private_bus_t *this)
{
static long current_num = 0;
- static long stored_num;
+ long stored_num;
stored_num = (long)pthread_getspecific(this->thread_id);
if (stored_num == 0)
@@ -180,7 +152,7 @@ static int get_thread_number(private_bus_t *this)
static void add_listener(private_bus_t *this, bus_listener_t *listener)
{
pthread_mutex_lock(&this->mutex);
- this->listeners->insert_last(this->listeners, listener);
+ this->listeners->insert_last(this->listeners, entry_create(listener, FALSE));
pthread_mutex_unlock(&this->mutex);
}
@@ -190,15 +162,16 @@ static void add_listener(private_bus_t *this, bus_listener_t *listener)
static void remove_listener(private_bus_t *this, bus_listener_t *listener)
{
iterator_t *iterator;
- bus_listener_t *current;
+ entry_t *entry;
pthread_mutex_lock(&this->mutex);
iterator = this->listeners->create_iterator(this->listeners, TRUE);
- while (iterator->iterate(iterator, (void**)&current))
+ while (iterator->iterate(iterator, (void**)&entry))
{
- if (current == listener)
+ if (entry->listener == listener)
{
iterator->remove(iterator);
+ free(entry);
break;
}
}
@@ -206,109 +179,67 @@ static void remove_listener(private_bus_t *this, bus_listener_t *listener)
pthread_mutex_unlock(&this->mutex);
}
+typedef struct cleanup_data_t cleanup_data_t;
+
+/**
+ * data to remove a listener using pthread_cleanup handler
+ */
+struct cleanup_data_t {
+ /** bus instance */
+ private_bus_t *this;
+ /** listener entry */
+ entry_t *entry;
+};
+
/**
- * Get the listener object for the calling thread
+ * pthread_cleanup handler to remove a listener
*/
-static active_listener_t *get_active_listener(private_bus_t *this)
+static void listener_cleanup(cleanup_data_t *data)
{
- active_listener_t *current, *found = NULL;
iterator_t *iterator;
-
- /* if the thread was here once before, we have a active_listener record */
- iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
- while (iterator->iterate(iterator, (void**)&current))
+ entry_t *entry;
+
+ iterator = data->this->listeners->create_iterator(data->this->listeners, TRUE);
+ while (iterator->iterate(iterator, (void**)&entry))
{
- if (current->id == pthread_self())
+ if (entry == data->entry)
{
- found = current;
+ iterator->remove(iterator);
+ free(entry);
break;
}
}
iterator->destroy(iterator);
-
- if (found == NULL)
- {
- /* create a new object for a never-seen thread */
- found = malloc_thing(active_listener_t);
- found->id = pthread_self();
- pthread_cond_init(&found->cond, NULL);
- this->active_listeners->insert_last(this->active_listeners, found);
- }
-
- return found;
-}
-
-/**
- * disable a listener to cleanly clean up
- */
-static void unregister(active_listener_t *listener)
-{
- listener->state = UNREGISTERED;
- pthread_cond_broadcast(&listener->cond);
}
/**
* Implementation of bus_t.listen.
*/
-static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
- ike_sa_t **ike_sa, char** format, va_list* args)
+static void listen_(private_bus_t *this, bus_listener_t *listener, job_t *job)
{
- active_listener_t *listener;
- int oldstate;
-
- pthread_mutex_lock(&this->mutex);
- listener = get_active_listener(this);
- /* go "listening", say hello to a thread which have a signal for us */
- listener->state = LISTENING;
- pthread_cond_broadcast(&listener->cond);
- /* wait until it has us delivered a signal, and go back to "registered".
- * we allow cancellation here, but must cleanly disable the listener. */
- pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex);
- pthread_cleanup_push((void*)unregister, listener);
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
- pthread_cond_wait(&listener->cond, &this->mutex);
- pthread_setcancelstate(oldstate, NULL);
- pthread_cleanup_pop(0);
- pthread_cleanup_pop(0);
-
- pthread_mutex_unlock(&this->mutex);
-
- /* return signal values */
- *level = listener->level;
- *thread = listener->thread;
- *ike_sa = listener->ike_sa;
- *format = listener->format;
- va_copy(*args, listener->args);
- va_end(listener->args);
+ int old;
+ cleanup_data_t data;
- return listener->signal;
-}
+ data.this = this;
+ data.entry = entry_create(listener, TRUE);
-/**
- * Implementation of bus_t.set_listen_state.
- */
-static void set_listen_state(private_bus_t *this, bool active)
-{
- active_listener_t *listener;
-
pthread_mutex_lock(&this->mutex);
-
- listener = get_active_listener(this);
- if (active)
- {
- listener->state = REGISTERED;
- }
- else
+ this->listeners->insert_last(this->listeners, data.entry);
+ charon->processor->queue_job(charon->processor, job);
+ pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex);
+ pthread_cleanup_push((void*)listener_cleanup, &data);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
+ while (data.entry->blocker)
{
- listener->state = UNREGISTERED;
- /* say hello to signal emitter; we are finished processing the signal */
- pthread_cond_broadcast(&listener->cond);
+ pthread_cond_wait(&data.entry->cond, &this->mutex);
}
-
- pthread_mutex_unlock(&this->mutex);
+ pthread_setcancelstate(old, NULL);
+ pthread_cleanup_pop(FALSE);
+ /* unlock mutex */
+ pthread_cleanup_pop(TRUE);
+ free(data.entry);
}
-
/**
* Implementation of bus_t.set_sa.
*/
@@ -324,72 +255,37 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
char* format, va_list args)
{
iterator_t *iterator;
- bus_listener_t *listener;
- active_listener_t *active_listener;
+ entry_t *entry;
ike_sa_t *ike_sa;
long thread;
+ pthread_mutex_lock(&this->mutex);
ike_sa = pthread_getspecific(this->thread_sa);
thread = get_thread_number(this);
- pthread_mutex_lock(&this->mutex);
-
- /* do the job for all passive bus_listeners */
iterator = this->listeners->create_iterator(this->listeners, TRUE);
- while (iterator->iterate(iterator, (void**)&listener))
+ while (iterator->iterate(iterator, (void**)&entry))
{
va_list args_copy;
va_copy(args_copy, args);
- if (!listener->signal(listener, signal, level, thread,
- ike_sa, format, args_copy))
+ if (!entry->listener->signal(entry->listener, signal, level, thread,
+ ike_sa, format, args_copy))
{
- /* unregister listener if requested */
iterator->remove(iterator);
+ if (entry->blocker)
+ {
+ entry->blocker = FALSE;
+ pthread_cond_signal(&entry->cond);
+ }
+ else
+ {
+ free(entry);
+ }
}
va_end(args_copy);
}
iterator->destroy(iterator);
- /* wake up all active listeners */
- iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
- while (iterator->iterate(iterator, (void**)&active_listener))
- {
- /* wait until all threads are registered. But if the thread raising
- * the signal is the same as the one that listens, we skip it.
- * Otherwise we would deadlock. */
- while (active_listener->id != pthread_self() &&
- active_listener->state == REGISTERED)
- {
- pthread_cond_wait(&active_listener->cond, &this->mutex);
- }
- /* if thread is listening now, give it the signal to process */
- if (active_listener->state == LISTENING)
- {
- active_listener->level = level;
- active_listener->thread = thread;
- active_listener->ike_sa = ike_sa;
- active_listener->signal = signal;
- active_listener->format = format;
- va_copy(active_listener->args, args);
- active_listener->state = REGISTERED;
- pthread_cond_broadcast(&active_listener->cond);
- }
- }
-
- /* we must wait now until all are not in state REGISTERED,
- * as they may still use our arguments */
- iterator->reset(iterator);
- while (iterator->iterate(iterator, (void**)&active_listener))
- {
- /* do not wait for ourself, it won't happen (see above) */
- while (active_listener->id != pthread_self() &&
- active_listener->state == REGISTERED)
- {
- pthread_cond_wait(&active_listener->cond, &this->mutex);
- }
- }
- iterator->destroy(iterator);
-
pthread_mutex_unlock(&this->mutex);
}
@@ -411,8 +307,7 @@ static void signal_(private_bus_t *this, signal_t signal, level_t level,
*/
static void destroy(private_bus_t *this)
{
- this->active_listeners->destroy_function(this->active_listeners, free);
- this->listeners->destroy(this->listeners);
+ this->listeners->destroy_function(this->listeners, free);
free(this);
}
@@ -425,18 +320,17 @@ bus_t *bus_create()
this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
this->public.remove_listener = (void(*)(bus_t*,bus_listener_t*))remove_listener;
- this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_;
- this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state;
+ this->public.listen = (void(*)(bus_t*, bus_listener_t *listener, job_t *job))listen_;
this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
this->public.destroy = (void(*)(bus_t*)) destroy;
this->listeners = linked_list_create();
- this->active_listeners = linked_list_create();
pthread_mutex_init(&this->mutex, NULL);
pthread_key_create(&this->thread_id, NULL);
pthread_key_create(&this->thread_sa, NULL);
- return &(this->public);
+ return &this->public;
}
+
diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h
index 00f1ab7ac..f71018444 100644
--- a/src/charon/bus/bus.h
+++ b/src/charon/bus/bus.h
@@ -32,6 +32,7 @@ typedef struct bus_t bus_t;
#include <sa/ike_sa.h>
#include <sa/child_sa.h>
+#include <processing/jobs/job.h>
/**
@@ -251,9 +252,7 @@ struct bus_listener_t {
* in receiving event signals registers at the bus. Any signals sent to
* are delivered to all registered listeners.
* To deliver signals to threads, the blocking listen() call may be used
- * to wait for a signal. However, passive listeners should be preferred,
- * as listening actively requires some synchronization overhead as data
- * must be passed from the raising thread to the listening thread.
+ * to wait for a signal.
*
* @ingroup bus
*/
@@ -280,44 +279,19 @@ struct bus_t {
void (*remove_listener) (bus_t *this, bus_listener_t *listener);
/**
- * @brief Listen actively on the bus.
+ * @brief Register a listener and block the calling thread.
*
- * As we are fully multithreaded, we must provide a mechanism
- * for active threads to listen to the bus. With the listen() method,
- * a thread waits until a signal occurs, and then processes it.
- * To prevent the listen() calling thread to miss signals emitted while
- * it processes a signal, registration is required. This is done through
- * the set_listen_state() method, see below.
- *
- * The listen() function is (has) a thread cancellation point, so you might
- * want to register cleanup handlers.
+ * This call registers a listener and blocks the calling thread until
+ * its listeners function returns FALSE. This allows to wait for certain
+ * events. The associated job is executed after the listener has been
+ * registered, this allows to listen on events we initiate with the job
+ * without missing any signals.
*
* @param this bus
- * @param level verbosity level of the signal
- * @param thread receives thread number emitted the signal
- * @param ike_sa receives the IKE_SA involved in the signal, or NULL
- * @param format receives the format string supplied with the signal
- * @param va_list receives the variable argument list for format
- * @return the emitted signal type
+ * @param listener listener to register
+ * @param job job to execute asynchronously when registered, or NULL
*/
- signal_t (*listen) (bus_t *this, level_t* level, int *thread,
- ike_sa_t **ike_sa, char** format, va_list* args);
-
- /**
- * @brief Set the listening state of the calling thread.
- *
- * To prevent message loss for active listeners using listen(), threads
- * must register themself to the bus before starting to listen(). When
- * a signal occurs, the emitter waits until all threads with listen_state
- * TRUE are waiting in the listen() method to process the signal.
- * It is important that a thread with listen_state TRUE calls listen()
- * periodically, or sets it's listening state to FALSE; otherwise
- * all signal emitting threads get blocked on the bus.
- *
- * @param this bus
- * @param active TRUE to set to listening
- */
- void (*set_listen_state) (bus_t *this, bool active);
+ void (*listen)(bus_t *this, bus_listener_t *listener, job_t *job);
/**
* @brief Set the IKE_SA the calling thread is using.
@@ -355,6 +329,10 @@ struct bus_t {
*
* Same as bus_t.signal(), but uses va_list argument list.
*
+ * @todo Improve performace of vsignal implementation. This method is
+ * called extensively and therefore shouldn't allocate heap memory or
+ * do other expensive tasks!
+ *
* @param this bus
* @param singal kind of the signal (up, down, rekeyed, ...)
* @param level verbosity level of the signal
diff --git a/src/charon/config/backends/sqlite_backend.c b/src/charon/config/backends/sqlite_backend.c
index 33093a735..e1c96c870 100644
--- a/src/charon/config/backends/sqlite_backend.c
+++ b/src/charon/config/backends/sqlite_backend.c
@@ -186,15 +186,15 @@ static peer_cfg_t *process_peer_cfg_row(private_sqlite_backend_t *this,
2, ike_cfg, local_id, remote_id, NULL, NULL, linked_list_create(),
sqlite3_column_int(stmt, 4), /* cert_policy */
sqlite3_column_int(stmt, 5), /* auth_method */
- sqlite3_column_int(stmt, 6), /* eap_type */
+ sqlite3_column_int(stmt, 6), 0 /* eap_type, vendor */
sqlite3_column_int(stmt, 7), /* keyingtries */
- sqlite3_column_int(stmt, 8), /* lifetime */
- sqlite3_column_int(stmt, 9), /* rekeytime */
- sqlite3_column_int(stmt, 10), /* jitter */
- sqlite3_column_int(stmt, 13), /* reauth */
+ sqlite3_column_int(stmt, 8), /* rekey_time */
+ sqlite3_column_int(stmt, 9), /* reauth_time */
+ sqlite3_column_int(stmt, 10), /* jitter_time */
+ sqlite3_column_int(stmt, 11), /* over_time */
sqlite3_column_int(stmt, 14), /* mobike */
- sqlite3_column_int(stmt, 11), /* dpd_delay */
- sqlite3_column_int(stmt, 12), /* dpd_action */
+ sqlite3_column_int(stmt, 12), /* dpd_delay */
+ sqlite3_column_int(stmt, 13), /* dpd_action */
local_vip, remote_vip, FALSE, NULL, NULL);
add_children(this, peer_cfg, sqlite3_column_int(stmt, 0));
return peer_cfg;
@@ -225,8 +225,9 @@ static peer_cfg_t *get_peer_cfg(private_sqlite_backend_t *this,
if (sqlite3_prepare_v2(this->db,
"SELECT peer_configs.oid, name, local_id, remote_id, cert_policy, "
- "auth_method, eap_type, keyingtries, lifetime, rekeytime, jitter, "
- "dpd_delay, dpd_action, reauth, mobike, local_vip, remote_vip, "
+ "auth_method, eap_type, keyingtries, "
+ "rekey_time, reauth_time, jitter_time, over_time, "
+ "dpd_delay, dpd_action, mobike, local_vip, remote_vip, "
"local, remote, certreq "
"FROM peer_configs, ike_configs "
"ON peer_configs.ike_cfg = ike_configs.oid "
diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c
index b71e9e9e2..b838f032d 100644
--- a/src/charon/config/credentials/local_credential_store.c
+++ b/src/charon/config/credentials/local_credential_store.c
@@ -18,6 +18,8 @@
* 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.
+ *
+ * RCSID $Id: local_credential_store.c 3346 2007-11-16 20:23:29Z andreas $
*/
#include <sys/stat.h>
@@ -1394,7 +1396,7 @@ static void load_secrets(private_local_credential_store_t *this, bool reload)
{
continue;
}
- if (!extract_token(&ids, ':', &line))
+ if (!extract_last_token(&ids, ':', &line))
{
DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr);
goto error;
diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c
index d61ed9512..0b5d391c4 100644
--- a/src/charon/config/peer_cfg.c
+++ b/src/charon/config/peer_cfg.c
@@ -127,14 +127,14 @@ struct private_peer_cfg_t {
eap_type_t eap_type;
/**
- * number of tries after giving up if peer does not respond
+ * EAP vendor ID if vendor specific type is used
*/
- u_int32_t keyingtries;
+ u_int32_t eap_vendor;
/**
- * user reauthentication instead of rekeying
+ * number of tries after giving up if peer does not respond
*/
- bool use_reauth;
+ u_int32_t keyingtries;
/**
* enable support for MOBIKE
@@ -142,20 +142,24 @@ struct private_peer_cfg_t {
bool use_mobike;
/**
- * Time before an SA gets invalid
+ * Time before starting rekeying
+ */
+ u_int32_t rekey_time;
+
+ /**
+ * Time before starting reauthentication
*/
- u_int32_t lifetime;
+ u_int32_t reauth_time;
/**
- * Time before an SA gets rekeyed
+ * Time, which specifies the range of a random value substracted from above.
*/
- u_int32_t rekeytime;
+ u_int32_t jitter_time;
/**
- * Time, which specifies the range of a random value
- * substracted from lifetime.
+ * Delay before deleting a rekeying/reauthenticating SA
*/
- u_int32_t jitter;
+ u_int32_t over_time;
/**
* What to do with an SA when other peer seams to be dead?
@@ -339,8 +343,9 @@ static auth_method_t get_auth_method(private_peer_cfg_t *this)
/**
* Implementation of connection_t.get_eap_type.
*/
-static eap_type_t get_eap_type(private_peer_cfg_t *this)
+static eap_type_t get_eap_type(private_peer_cfg_t *this, u_int32_t *vendor)
{
+ *vendor = this->eap_vendor;
return this->eap_type;
}
@@ -353,29 +358,45 @@ static u_int32_t get_keyingtries(private_peer_cfg_t *this)
}
/**
- * Implementation of peer_cfg_t.get_soft_lifetime
+ * Implementation of peer_cfg_t.get_rekey_time.
*/
-static u_int32_t get_lifetime(private_peer_cfg_t *this, bool rekey)
+static u_int32_t get_rekey_time(private_peer_cfg_t *this)
{
- if (rekey)
+ if (this->rekey_time == 0)
{
- if (this->jitter == 0)
- {
- return this->rekeytime;
- }
- return this->rekeytime - (random() % this->jitter);
+ return 0;
+ }
+ if (this->jitter_time == 0)
+ {
+ return this->rekey_time;
}
- return this->lifetime;
+ return this->rekey_time - (random() % this->jitter_time);
}
-
+
+/**
+ * Implementation of peer_cfg_t.get_reauth_time.
+ */
+static u_int32_t get_reauth_time(private_peer_cfg_t *this)
+{
+ if (this->reauth_time == 0)
+ {
+ return 0;
+ }
+ if (this->jitter_time == 0)
+ {
+ return this->reauth_time;
+ }
+ return this->reauth_time - (random() % this->jitter_time);
+}
+
/**
- * Implementation of peer_cfg_t.use_reauth.
+ * Implementation of peer_cfg_t.get_over_time.
*/
-static bool use_reauth(private_peer_cfg_t *this)
+static u_int32_t get_over_time(private_peer_cfg_t *this)
{
- return this->use_reauth;
+ return this->over_time;
}
-
+
/**
* Implementation of peer_cfg_t.use_mobike.
*/
@@ -503,9 +524,10 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
identification_t *my_ca, identification_t *other_ca,
linked_list_t *groups, cert_policy_t cert_policy,
auth_method_t auth_method, eap_type_t eap_type,
- u_int32_t keyingtries, u_int32_t lifetime,
- u_int32_t rekeytime, u_int32_t jitter,
- bool reauth, bool mobike,
+ u_int32_t eap_vendor,
+ u_int32_t keyingtries, u_int32_t rekey_time,
+ u_int32_t reauth_time, u_int32_t jitter_time,
+ u_int32_t over_time, bool mobike,
u_int32_t dpd_delay, dpd_action_t dpd_action,
host_t *my_virtual_ip, host_t *other_virtual_ip,
bool p2p_mediation, peer_cfg_t *p2p_mediated_by,
@@ -527,10 +549,11 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
this->public.get_groups = (linked_list_t* (*)(peer_cfg_t *))get_groups;
this->public.get_cert_policy = (cert_policy_t (*) (peer_cfg_t *))get_cert_policy;
this->public.get_auth_method = (auth_method_t (*) (peer_cfg_t *))get_auth_method;
- this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *))get_eap_type;
+ this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *,u_int32_t*))get_eap_type;
this->public.get_keyingtries = (u_int32_t (*) (peer_cfg_t *))get_keyingtries;
- this->public.get_lifetime = (u_int32_t (*) (peer_cfg_t *, bool rekey))get_lifetime;
- this->public.use_reauth = (bool (*) (peer_cfg_t *))use_reauth;
+ this->public.get_rekey_time = (u_int32_t(*)(peer_cfg_t*))get_rekey_time;
+ this->public.get_reauth_time = (u_int32_t(*)(peer_cfg_t*))get_reauth_time;
+ this->public.get_over_time = (u_int32_t(*)(peer_cfg_t*))get_over_time;
this->public.use_mobike = (bool (*) (peer_cfg_t *))use_mobike;
this->public.get_dpd_delay = (u_int32_t (*) (peer_cfg_t *))get_dpd_delay;
this->public.get_dpd_action = (dpd_action_t (*) (peer_cfg_t *))get_dpd_action;
@@ -558,11 +581,20 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
this->cert_policy = cert_policy;
this->auth_method = auth_method;
this->eap_type = eap_type;
+ this->eap_vendor = eap_vendor;
this->keyingtries = keyingtries;
- this->lifetime = lifetime;
- this->rekeytime = rekeytime;
- this->jitter = jitter;
- this->use_reauth = reauth;
+ this->rekey_time = rekey_time;
+ this->reauth_time = reauth_time;
+ if (rekey_time && jitter_time > rekey_time)
+ {
+ jitter_time = rekey_time;
+ }
+ if (reauth_time && jitter_time > reauth_time)
+ {
+ jitter_time = reauth_time;
+ }
+ this->jitter_time = jitter_time;
+ this->over_time = over_time;
this->use_mobike = mobike;
this->dpd_delay = dpd_delay;
this->dpd_action = dpd_action;
diff --git a/src/charon/config/peer_cfg.h b/src/charon/config/peer_cfg.h
index 3d238e6aa..7f1dbcab6 100644
--- a/src/charon/config/peer_cfg.h
+++ b/src/charon/config/peer_cfg.h
@@ -229,11 +229,16 @@ struct peer_cfg_t {
/**
* @brief Get the EAP type to use for peer authentication.
+ *
+ * If vendor specific types are used, a vendor ID != 0 is returned to
+ * to vendor argument. Then the returned type is specific for that
+ * vendor ID.
*
* @param this calling object
+ * @param vendor receives vendor specifier, 0 for predefined EAP types
* @return authentication method
*/
- eap_type_t (*get_eap_type) (peer_cfg_t *this);
+ eap_type_t (*get_eap_type) (peer_cfg_t *this, u_int32_t *vendor);
/**
* @brief Get the max number of retries after timeout.
@@ -244,27 +249,28 @@ struct peer_cfg_t {
u_int32_t (*get_keyingtries) (peer_cfg_t *this);
/**
- * @brief Get the lifetime of a IKE_SA.
+ * @brief Get a time to start rekeying (is randomized with jitter).
*
- * If "rekey" is set to TRUE, a lifetime is returned before the first
- * rekeying should be started. If it is FALSE, the actual lifetime is
- * returned when the IKE_SA must be deleted.
- * The rekey time automatically contains a jitter to avoid simlutaneous
- * rekeying.
- *
- * @param this child_config
- * @param rekey TRUE to get rekey time
- * @return lifetime in seconds
+ * @param this calling object
+ * @return time in s when to start rekeying, 0 disables rekeying
*/
- u_int32_t (*get_lifetime) (peer_cfg_t *this, bool rekey);
+ u_int32_t (*get_rekey_time)(peer_cfg_t *this);
/**
- * @brief Should a full reauthentication be done instead of rekeying?
- *
+ * @brief Get a time to start reauthentication (is randomized with jitter).
+ *
* @param this calling object
- * @return TRUE to use full reauthentication
+ * @return time in s when to start reauthentication, 0 disables it
+ */
+ u_int32_t (*get_reauth_time)(peer_cfg_t *this);
+
+ /**
+ * @brief Get the timeout of a rekeying/reauthenticating SA.
+ *
+ * @param thsi calling object
+ * @return timeout in s
*/
- bool (*use_reauth) (peer_cfg_t *this);
+ u_int32_t (*get_over_time)(peer_cfg_t *this);
/**
* @brief Use MOBIKE (RFC4555) if peer supports it?
@@ -392,10 +398,12 @@ struct peer_cfg_t {
* @param cert_policy should we send a certificate payload?
* @param auth_method auth method to use to authenticate us
* @param eap_type EAP type to use for peer authentication
+ * @param eap_vendor EAP vendor identifier, if vendor specific type is used
* @param keyingtries how many keying tries should be done before giving up
- * @param lifetime lifetime before deleting an SA
- * @param rekeytime lifetime before rekeying an SA
- * @param jitter range of random to substract from rekeytime
+ * @param rekey_time timeout before starting rekeying
+ * @param reauth_time timeout before starting reauthentication
+ * @param jitter_time timerange to randomly substract from rekey/reauth time
+ * @param over_time maximum overtime before closing a rekeying/reauth SA
* @param reauth sould be done reauthentication instead of rekeying?
* @param mobike use MOBIKE (RFC4555) if peer supports it
* @param dpd_delay after how many seconds of inactivity to check DPD
@@ -414,9 +422,10 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg,
identification_t *my_ca, identification_t *other_ca,
linked_list_t *groups, cert_policy_t cert_policy,
auth_method_t auth_method, eap_type_t eap_type,
- u_int32_t keyingtries, u_int32_t lifetime,
- u_int32_t rekeytime, u_int32_t jitter,
- bool reauth, bool mobike,
+ u_int32_t eap_vendor,
+ u_int32_t keyingtries, u_int32_t rekey_time,
+ u_int32_t reauth_time, u_int32_t jitter_time,
+ u_int32_t over_time, bool mobike,
u_int32_t dpd_delay, dpd_action_t dpd_action,
host_t *my_virtual_ip, host_t *other_virtual_ip,
bool p2p_mediation, peer_cfg_t *p2p_mediated_by,
diff --git a/src/charon/control/interface_manager.c b/src/charon/control/interface_manager.c
index c71036567..c14903c7d 100644
--- a/src/charon/control/interface_manager.c
+++ b/src/charon/control/interface_manager.c
@@ -56,18 +56,24 @@ struct private_interface_manager_t {
linked_list_t *handles;
};
+
/**
* helper struct to map bus listener callbacks to interface callbacks
*/
struct interface_bus_listener_t {
/**
- * bus listener callback function (called)
+ * public bus listener interface
*/
- bus_listener_t listener;
+ bus_listener_t public;
+
+ /**
+ * status of the operation, return to method callers
+ */
+ status_t status;
/**
- * IKE_SA to use for message filtering
+ * IKE SA to filter log output
*/
ike_sa_t *ike_sa;
@@ -82,12 +88,48 @@ struct interface_bus_listener_t {
void *param;
/**
- * caller has cancelled its listening subscription
+ * child configuration, used for initiate
+ */
+ child_cfg_t *child_cfg;
+
+ /**
+ * peer configuration, used for initiate
+ */
+ peer_cfg_t *peer_cfg;
+
+ /**
+ * unique ID, used for various methods
+ */
+ u_int32_t id;
+};
+
+
+typedef struct interface_job_t interface_job_t;
+
+/**
+ * job for asynchronous listen operations
+ */
+struct interface_job_t {
+ /**
+ * job interface
+ */
+ job_t public;
+
+ /**
+ * associated listener
*/
- bool cancelled;
+ interface_bus_listener_t listener;
};
/**
+ * Implements the famous nop operation
+ */
+static void nop(job_t *job)
+{
+ /* NOP */
+}
+
+/**
* Implementation of interface_manager_t.create_ike_sa_iterator.
*/
static iterator_t* create_ike_sa_iterator(interface_manager_t *this)
@@ -106,17 +148,16 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal,
{
if (!this->callback(this->param, signal, level, ike_sa, format, args))
{
- this->cancelled = TRUE;
return FALSE;
}
switch (signal)
{
+ case CHILD_UP_SUCCESS:
+ this->status = SUCCESS;
+ return FALSE;
case IKE_UP_FAILED:
case CHILD_UP_FAILED:
- case CHILD_UP_SUCCESS:
- {
return FALSE;
- }
default:
break;
}
@@ -125,112 +166,82 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal,
}
/**
- * listener function for terminate_ike
+ * execute function for initiate
*/
-static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal,
- level_t level, int thread, ike_sa_t *ike_sa,
- char* format, va_list args)
+static status_t initiate_execute(interface_job_t *job)
{
- if (this->ike_sa == ike_sa)
+ ike_sa_t *ike_sa;
+ ike_cfg_t *ike_cfg;
+ interface_bus_listener_t *listener = &job->listener;
+ peer_cfg_t *peer_cfg = listener->peer_cfg;
+
+ ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+ ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
+ ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg),
+ peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg));
+ listener->ike_sa = ike_sa;
+
+ if (ike_sa->get_peer_cfg(ike_sa) == NULL)
{
- if (!this->callback(this->param, signal, level, ike_sa, format, args))
- {
- this->cancelled = TRUE;
- return FALSE;
- }
- switch (signal)
- {
- case IKE_DOWN_FAILED:
- case IKE_DOWN_SUCCESS:
- {
- return FALSE;
- }
- default:
- break;
- }
+ ike_sa->set_peer_cfg(ike_sa, peer_cfg);
}
- return TRUE;
-}
-
-/**
- * listener function for terminate_child
- */
-static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal,
- level_t level, int thread, ike_sa_t *ike_sa,
- char* format, va_list args)
-{
- if (this->ike_sa == ike_sa)
+ peer_cfg->destroy(peer_cfg);
+
+ if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS)
{
- if (!this->callback(this->param, signal, level, ike_sa, format, args))
- {
- this->cancelled = TRUE;
- return FALSE;
- }
- switch (signal)
- {
- case IKE_DOWN_FAILED:
- case IKE_DOWN_SUCCESS:
- case CHILD_DOWN_FAILED:
- case CHILD_DOWN_SUCCESS:
- {
- return FALSE;
- }
- default:
- break;
- }
+ return charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
}
- return TRUE;
+ return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
/**
- * listener function for route
+ * Implementation of interface_manager_t.initiate.
*/
-static bool route_listener(interface_bus_listener_t *this, signal_t signal,
- level_t level, int thread, ike_sa_t *ike_sa,
- char* format, va_list args)
+static status_t initiate(private_interface_manager_t *this,
+ peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
+ interface_manager_cb_t callback, void *param)
{
- if (this->ike_sa == ike_sa)
+ interface_job_t job;
+
+ job.listener.public.signal = (void*)initiate_listener;
+ job.listener.ike_sa = NULL;
+ job.listener.callback = callback;
+ job.listener.param = param;
+ job.listener.status = FAILED;
+ job.listener.child_cfg = child_cfg;
+ job.listener.peer_cfg = peer_cfg;
+ job.public.execute = (void*)initiate_execute;
+ job.public.destroy = nop;
+
+ if (callback == NULL)
{
- if (!this->callback(this->param, signal, level, ike_sa, format, args))
- {
- this->cancelled = TRUE;
- return FALSE;
- }
- switch (signal)
- {
- case CHILD_ROUTE_SUCCESS:
- case CHILD_ROUTE_FAILED:
- {
- return FALSE;
- }
- default:
- break;
- }
+ return initiate_execute(&job);
}
- return TRUE;
+ charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
+ return job.listener.status;
}
/**
- * listener function for unroute
+ * listener function for terminate_ike
*/
-static bool unroute_listener(interface_bus_listener_t *this, signal_t signal,
- level_t level, int thread, ike_sa_t *ike_sa,
- char* format, va_list args)
+static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal,
+ level_t level, int thread, ike_sa_t *ike_sa,
+ char* format, va_list args)
{
if (this->ike_sa == ike_sa)
{
if (!this->callback(this->param, signal, level, ike_sa, format, args))
{
- this->cancelled = TRUE;
return FALSE;
}
switch (signal)
{
- case CHILD_UNROUTE_SUCCESS:
- case CHILD_UNROUTE_FAILED:
- {
+ case IKE_DOWN_SUCCESS:
+ this->status = SUCCESS;
+ return FALSE;
+ case IKE_DOWN_FAILED:
return FALSE;
- }
default:
break;
}
@@ -239,102 +250,29 @@ static bool unroute_listener(interface_bus_listener_t *this, signal_t signal,
}
/**
- * remove a previously registered listener from the bus
+ * execute function for terminate_ike
*/
-static void remove_listener(interface_bus_listener_t *listener)
-{
- charon->bus->remove_listener(charon->bus, &listener->listener);
-}
-
-/**
- * Implementation of interface_manager_t.initiate.
- */
-static status_t initiate(private_interface_manager_t *this,
- peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
- interface_manager_cb_t callback, void *param)
+static status_t terminate_ike_execute(interface_job_t *job)
{
ike_sa_t *ike_sa;
- ike_cfg_t *ike_cfg;
- status_t retval = FAILED;
- interface_bus_listener_t listener;
+ interface_bus_listener_t *listener = &job->listener;
- ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
- ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
- ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg),
- peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg));
-
- if (ike_sa->get_peer_cfg(ike_sa) == NULL)
- {
- ike_sa->set_peer_cfg(ike_sa, peer_cfg);
- }
- peer_cfg->destroy(peer_cfg);
-
- listener.listener.signal = (void*)initiate_listener;
- listener.callback = callback;
- listener.ike_sa = ike_sa;
- listener.param = param;
- listener.cancelled = FALSE;
-
- /* we listen passively to catch the signals we are raising in
- * ike_sa->delete(). */
- if (callback)
- {
- charon->bus->add_listener(charon->bus, &listener.listener);
- }
- charon->bus->set_listen_state(charon->bus, TRUE);
- if (ike_sa->initiate(ike_sa, child_cfg) != SUCCESS)
- {
- charon->bus->set_listen_state(charon->bus, FALSE);
- charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
- return FAILED;
- }
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-
- if (callback == NULL)
+ ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+ listener->id, FALSE);
+ if (ike_sa == NULL)
{
- /* don't wait for a result if no callback is specified */
- charon->bus->set_listen_state(charon->bus, FALSE);
- return NEED_MORE;
- }
+ SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with "
+ "ID %d not found", listener->id);
+ return NOT_FOUND;
+ }
+ listener->ike_sa = ike_sa;
- /* wait until we get a result */
- while (TRUE)
+ if (ike_sa->delete(ike_sa) == DESTROY_ME)
{
- level_t level;
- signal_t signal;
- int thread;
- ike_sa_t *current;
- char* format;
- va_list args;
-
- /* stop listening if the passive listener returned FALSE */
- if (listener.cancelled)
- {
- retval = NEED_MORE;
- break;
- }
- pthread_cleanup_push((void*)remove_listener, &listener);
- signal = charon->bus->listen(charon->bus, &level, &thread,
- &current, &format, &args);
- pthread_cleanup_pop(0);
- /* ike_sa is a valid pointer until we get one of the signals */
- if (ike_sa == current)
- {
- switch (signal)
- {
- case CHILD_UP_SUCCESS:
- retval = SUCCESS;
- case CHILD_UP_FAILED:
- case IKE_UP_FAILED:
- break;
- default:
- continue;
- }
- break;
- }
+ return charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
}
- charon->bus->set_listen_state(charon->bus, FALSE);
- return retval;
+ return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
/**
@@ -343,107 +281,78 @@ static status_t initiate(private_interface_manager_t *this,
static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id,
interface_manager_cb_t callback, void *param)
{
- ike_sa_t *ike_sa;
- status_t status = FAILED;;
- interface_bus_listener_t listener;
+ interface_job_t job;
- ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- unique_id, FALSE);
- if (ike_sa == NULL)
- {
- return NOT_FOUND;
- }
-
- /* we listen passively to catch the signals we are raising in
- * ike_sa->delete(). */
- listener.listener.signal = (void*)terminate_ike_listener;
- listener.callback = callback;
- listener.ike_sa = ike_sa;
- listener.param = param;
- listener.cancelled = FALSE;
- if (callback)
- {
- charon->bus->add_listener(charon->bus, &listener.listener);
- }
- charon->bus->set_listen_state(charon->bus, TRUE);
- status = ike_sa->delete(ike_sa);
- if (status == DESTROY_ME)
+ job.listener.public.signal = (void*)terminate_ike_listener;
+ job.listener.ike_sa = NULL;
+ job.listener.callback = callback;
+ job.listener.param = param;
+ job.listener.status = FAILED;
+ job.listener.id = unique_id;
+ job.public.execute = (void*)terminate_ike_execute;
+ job.public.destroy = nop;
+
+ if (callback == NULL)
{
- charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ return terminate_ike_execute(&job);
}
- else
+ charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
+ return job.listener.status;
+}
+/**
+ * listener function for terminate_child
+ */
+static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal,
+ level_t level, int thread, ike_sa_t *ike_sa,
+ char* format, va_list args)
+{
+ if (this->ike_sa == ike_sa)
{
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-
- /* wait until IKE_SA is cleanly deleted using a delete message */
- while (TRUE)
+ if (!this->callback(this->param, signal, level, ike_sa, format, args))
{
- level_t level;
- signal_t signal;
- int thread;
- ike_sa_t *current;
- char* format;
- va_list args;
-
- /* stop listening if the passive listener returned FALSE */
- if (listener.cancelled)
- {
- status = NEED_MORE;
- break;
- }
- pthread_cleanup_push((void*)remove_listener, &listener);
- signal = charon->bus->listen(charon->bus, &level, &thread,
- &current, &format, &args);
- pthread_cleanup_pop(0);
-
- /* even if we checked in the IKE_SA, the pointer is valid until
- * we get an IKE_DOWN_... */
- if (ike_sa == current)
- {
- switch (signal)
- {
- case IKE_DOWN_FAILED:
- case IKE_DOWN_SUCCESS:
- {
- status = SUCCESS;
- break;
- }
- default:
- continue;
- }
+ return FALSE;
+ }
+ switch (signal)
+ {
+ case CHILD_DOWN_SUCCESS:
+ case IKE_DOWN_SUCCESS:
+ this->status = SUCCESS;
+ return FALSE;
+ case IKE_DOWN_FAILED:
+ case CHILD_DOWN_FAILED:
+ return FALSE;
+ default:
break;
- }
}
}
- charon->bus->set_listen_state(charon->bus, FALSE);
-
- return status;
+ return TRUE;
}
/**
- * Implementation of interface_manager_t.terminate_child.
+ * execute function for terminate_child
*/
-static status_t terminate_child(interface_manager_t *this, u_int32_t reqid,
- interface_manager_cb_t callback, void *param)
+static status_t terminate_child_execute(interface_job_t *job)
{
ike_sa_t *ike_sa;
child_sa_t *child_sa;
iterator_t *iterator;
- status_t status = FAILED;
- interface_bus_listener_t listener;
+ interface_bus_listener_t *listener = &job->listener;
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- reqid, TRUE);
+ listener->id, TRUE);
if (ike_sa == NULL)
{
+ SIG(CHILD_DOWN_FAILED, "unable to terminate, CHILD_SA with "
+ "ID %d not found", listener->id);
return NOT_FOUND;
}
+ listener->ike_sa = ike_sa;
iterator = ike_sa->create_child_sa_iterator(ike_sa);
while (iterator->iterate(iterator, (void**)&child_sa))
{
if (child_sa->get_state(child_sa) != CHILD_ROUTED &&
- child_sa->get_reqid(child_sa) == reqid)
+ child_sa->get_reqid(child_sa) == listener->id)
{
break;
}
@@ -453,160 +362,203 @@ static status_t terminate_child(interface_manager_t *this, u_int32_t reqid,
if (child_sa == NULL)
{
+ SIG(CHILD_DOWN_FAILED, "unable to terminate, established CHILD_SA with "
+ "ID %d not found", listener->id);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return NOT_FOUND;
}
- listener.listener.signal = (void*)terminate_child_listener;
- listener.callback = callback;
- listener.ike_sa = ike_sa;
- listener.param = param;
- listener.cancelled = FALSE;
-
- /* we listen passively to catch the signals we are raising */
- if (callback)
+ if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
+ child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME)
{
- charon->bus->add_listener(charon->bus, &listener.listener);
+ return charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
}
- charon->bus->set_listen_state(charon->bus, TRUE);
- status = ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE));
- if (status == DESTROY_ME)
+ return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+}
+
+/**
+ * Implementation of interface_manager_t.terminate_child.
+ */
+static status_t terminate_child(interface_manager_t *this, u_int32_t reqid,
+ interface_manager_cb_t callback, void *param)
+{
+ interface_job_t job;
+
+ job.listener.public.signal = (void*)terminate_child_listener;
+ job.listener.ike_sa = NULL;
+ job.listener.callback = callback;
+ job.listener.param = param;
+ job.listener.status = FAILED;
+ job.listener.id = reqid;
+ job.public.execute = (void*)terminate_child_execute;
+ job.public.destroy = nop;
+
+ if (callback == NULL)
{
- charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ return terminate_child_execute(&job);
}
- else
+ charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
+ return job.listener.status;
+}
+
+/**
+ * listener function for route
+ */
+static bool route_listener(interface_bus_listener_t *this, signal_t signal,
+ level_t level, int thread, ike_sa_t *ike_sa,
+ char* format, va_list args)
+{
+ if (this->ike_sa == ike_sa)
{
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-
- /* wait until CHILD_SA is cleanly deleted using a delete message */
- while (TRUE)
+ if (!this->callback(this->param, signal, level, ike_sa, format, args))
{
- level_t level;
- signal_t signal;
- int thread;
- ike_sa_t *current;
- char* format;
- va_list args;
-
- /* stop listening if the passive listener returned FALSE */
- if (listener.cancelled)
- {
- status = NEED_MORE;
- break;
- }
- pthread_cleanup_push((void*)remove_listener, &listener);
- signal = charon->bus->listen(charon->bus, &level, &thread,
- &current, &format, &args);
- pthread_cleanup_pop(0);
- /* even if we checked in the IKE_SA, the pointer is valid until
- * we get an IKE_DOWN_... */
- if (ike_sa == current)
- {
- switch (signal)
- {
- case IKE_DOWN_FAILED:
- case IKE_DOWN_SUCCESS:
- case CHILD_DOWN_FAILED:
- case CHILD_DOWN_SUCCESS:
- {
- status = SUCCESS;
- break;
- }
- default:
- continue;
- }
+ return FALSE;
+ }
+ switch (signal)
+ {
+ case CHILD_ROUTE_SUCCESS:
+ this->status = SUCCESS;
+ return FALSE;
+ case CHILD_ROUTE_FAILED:
+ return FALSE;
+ default:
break;
- }
}
}
- charon->bus->set_listen_state(charon->bus, FALSE);
-
- return status;
+ return TRUE;
}
/**
- * Implementation of interface_manager_t.route.
+ * execute function for route
*/
-static status_t route(interface_manager_t *this,
- peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
- interface_manager_cb_t callback, void *param)
+static status_t route_execute(interface_job_t *job)
{
ike_sa_t *ike_sa;
ike_cfg_t *ike_cfg;
- status_t status = SUCCESS;
+ interface_bus_listener_t *listener = &job->listener;
+ peer_cfg_t *peer_cfg = listener->peer_cfg;
ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg),
peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg));
+ listener->ike_sa = ike_sa;
if (ike_sa->get_peer_cfg(ike_sa) == NULL)
{
ike_sa->set_peer_cfg(ike_sa, peer_cfg);
}
-
- /* we listen passively only, as routing is done by one thread only */
- if (callback)
+ if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME)
{
- interface_bus_listener_t listener;
-
- listener.listener.signal = (void*)route_listener;
- listener.callback = callback;
- listener.ike_sa = ike_sa;
- listener.param = param;
- listener.cancelled = FALSE;
- charon->bus->add_listener(charon->bus, &listener.listener);
+ return charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
}
+ return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+}
+
+/**
+ * Implementation of interface_manager_t.route.
+ */
+static status_t route(interface_manager_t *this,
+ peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
+ interface_manager_cb_t callback, void *param)
+{
+ interface_job_t job;
- if (ike_sa->route(ike_sa, child_cfg) != SUCCESS)
+ job.listener.public.signal = (void*)route_listener;
+ job.listener.ike_sa = NULL;
+ job.listener.callback = callback;
+ job.listener.param = param;
+ job.listener.status = FAILED;
+ job.listener.peer_cfg = peer_cfg;
+ job.listener.child_cfg = child_cfg;
+ job.public.execute = (void*)route_execute;
+ job.public.destroy = nop;
+
+ if (callback == NULL)
{
- status = FAILED;
+ return route_execute(&job);
}
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- return status;
+ charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
+ return job.listener.status;
}
/**
- * Implementation of interface_manager_t.unroute.
+ * listener function for unroute
*/
-static status_t unroute(interface_manager_t *this, u_int32_t reqid,
- interface_manager_cb_t callback, void *param)
+static bool unroute_listener(interface_bus_listener_t *this, signal_t signal,
+ level_t level, int thread, ike_sa_t *ike_sa,
+ char* format, va_list args)
+{
+ if (this->ike_sa == ike_sa)
+ {
+ if (!this->callback(this->param, signal, level, ike_sa, format, args))
+ {
+ return FALSE;
+ }
+ switch (signal)
+ {
+ case CHILD_UNROUTE_SUCCESS:
+ this->status = SUCCESS;
+ return FALSE;
+ case CHILD_UNROUTE_FAILED:
+ return FALSE;
+ default:
+ break;
+ }
+ }
+ return TRUE;
+}
+/**
+ * execute function for unroute
+ */
+static status_t unroute_execute(interface_job_t *job)
{
ike_sa_t *ike_sa;
- status_t status;
+ interface_bus_listener_t *listener = &job->listener;
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- reqid, TRUE);
+ listener->id, TRUE);
if (ike_sa == NULL)
{
+ SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with "
+ "ID %d not found", listener->id);
return NOT_FOUND;
}
-
- /* we listen passively only, as routing is done by one thread only */
- if (callback)
+ listener->ike_sa = ike_sa;
+ if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME)
{
- interface_bus_listener_t listener;
-
- listener.listener.signal = (void*)unroute_listener;
- listener.callback = callback;
- listener.ike_sa = ike_sa;
- listener.param = param;
- listener.cancelled = FALSE;
- charon->bus->add_listener(charon->bus, &listener.listener);
+ return charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
}
- status = ike_sa->unroute(ike_sa, reqid);
- if (status == DESTROY_ME)
- {
- charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
- status = SUCCESS;
- }
- else
+ return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+}
+
+/**
+ * Implementation of interface_manager_t.unroute.
+ */
+static status_t unroute(interface_manager_t *this, u_int32_t reqid,
+ interface_manager_cb_t callback, void *param)
+{
+ interface_job_t job;
+
+ job.listener.public.signal = (void*)unroute_listener;
+ job.listener.ike_sa = NULL;
+ job.listener.callback = callback;
+ job.listener.param = param;
+ job.listener.status = FAILED;
+ job.listener.id = reqid;
+ job.public.execute = (void*)unroute_execute;
+ job.public.destroy = nop;
+
+ if (callback == NULL)
{
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return unroute_execute(&job);
}
- return status;
+ charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
+ return job.listener.status;
}
/**
diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c
index 66ed423ae..b51d53ebd 100755
--- a/src/charon/control/interfaces/stroke_interface.c
+++ b/src/charon/control/interfaces/stroke_interface.c
@@ -239,13 +239,13 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
bool other_ca_same =FALSE;
host_t *my_host, *other_host, *my_subnet, *other_subnet;
host_t *my_vip = NULL, *other_vip = NULL;
- linked_list_t *my_groups = linked_list_create();
linked_list_t *other_groups = linked_list_create();
proposal_t *proposal;
traffic_selector_t *my_ts, *other_ts;
char *interface;
bool use_existing = FALSE;
iterator_t *iterator;
+ u_int32_t vendor;
pop_string(msg, &msg->add_conn.name);
DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
@@ -262,7 +262,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
DBG2(DBG_CFG, " p2p_mediated_by=%s", msg->add_conn.p2p.mediated_by);
DBG2(DBG_CFG, " p2p_peerid=%s", msg->add_conn.p2p.peerid);
- my_host = msg->add_conn.me.address?
+ my_host = msg->add_conn.me.address ?
host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL;
if (my_host == NULL)
{
@@ -365,11 +365,11 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
}
}
else
-#endif /* P2P */
{
- // no peer ID supplied, assume right ID
+ /* no peer ID supplied, assume right ID */
peer_id = other_id->clone(other_id);
}
+#endif /* P2P */
my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
@@ -544,7 +544,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
&& ietfAttr_list_equals(other_groups, peer_cfg->get_groups(peer_cfg))
&& peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1)
&& peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method
- && peer_cfg->get_eap_type(peer_cfg) == msg->add_conn.eap_type)
+ && peer_cfg->get_eap_type(peer_cfg, &vendor) == msg->add_conn.eap_type
+ && vendor == msg->add_conn.eap_vendor)
{
DBG1(DBG_CFG, "reusing existing configuration '%s'",
peer_cfg->get_name(peer_cfg));
@@ -564,9 +565,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
other_host->destroy(other_host);
other_id->destroy(other_id);
other_ca->destroy(other_ca);
- peer_id->destroy(peer_id);
+ DESTROY_IF(peer_id);
DESTROY_IF(mediated_by_cfg);
- ietfAttr_list_destroy(my_groups);
ietfAttr_list_destroy(other_groups);
}
else
@@ -613,15 +613,25 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
ike_cfg->add_proposal(ike_cfg, proposal);
}
+ u_int32_t rekey = 0, reauth = 0, over, jitter;
+
+ jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
+ over = msg->add_conn.rekey.margin;
+ if (msg->add_conn.rekey.reauth)
+ {
+ reauth = msg->add_conn.rekey.ike_lifetime - over;
+ }
+ else
+ {
+ rekey = msg->add_conn.rekey.ike_lifetime - over;
+ }
peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1,
ike_cfg, my_id, other_id, my_ca, other_ca, other_groups,
- msg->add_conn.me.sendcert,
- msg->add_conn.auth_method, msg->add_conn.eap_type,
- msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime,
- msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
- msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
- msg->add_conn.rekey.reauth, msg->add_conn.mobike,
+ msg->add_conn.me.sendcert, msg->add_conn.auth_method,
+ msg->add_conn.eap_type, msg->add_conn.eap_vendor,
+ msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
+ msg->add_conn.mobike,
msg->add_conn.dpd.delay, msg->add_conn.dpd.action, my_vip, other_vip,
msg->add_conn.p2p.mediation, mediated_by_cfg, peer_id);
}
@@ -1104,9 +1114,8 @@ static void stroke_del_ca(stroke_msg_t *msg, FILE *out)
*/
static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
{
- peer_cfg_t *cfg = ike_sa->get_peer_cfg(ike_sa);
ike_sa_id_t *id = ike_sa->get_id(ike_sa);
- u_int32_t next, now = time(NULL);
+ u_int32_t rekey, reauth;
fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
@@ -1116,21 +1125,26 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
if (all)
{
- fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s, ",
+ fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
- ike_sa->get_stats(ike_sa, &next);
- if (next)
+ rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME);
+ reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME);
+ if (rekey)
{
- fprintf(out, "%s in %V\n", cfg->use_reauth(cfg) ?
- "reauthentication" : "rekeying", &now, &next);
+ fprintf(out, ", rekeying in %V", &rekey);
}
- else
+ if (reauth)
{
- fprintf(out, "rekeying disabled\n");
+ fprintf(out, ", reauthentication in %V", &reauth);
}
+ if (!rekey && !reauth)
+ {
+ fprintf(out, ", rekeying disabled");
+ }
+ fprintf(out, "\n");
}
}
@@ -1188,7 +1202,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
if (rekey)
{
- fprintf(out, "in %V", &now, &rekey);
+ fprintf(out, "in %#V", &now, &rekey);
}
else
{
@@ -1692,7 +1706,6 @@ static job_requeue_t stroke_process(int *fdp)
return JOB_REQUEUE_NONE;
}
-
/**
* Implementation of private_stroke_interface_t.stroke_receive.
*/
diff --git a/src/charon/control/interfaces/xml_interface.c b/src/charon/control/interfaces/xml_interface.c
index 02da1064d..aa2a554a0 100644
--- a/src/charon/control/interfaces/xml_interface.c
+++ b/src/charon/control/interfaces/xml_interface.c
@@ -91,6 +91,9 @@ static void write_id(xmlTextWriterPtr writer, char *element, identification_t *i
char *type = "";
while (TRUE)
{
+ case ID_ANY:
+ type = "any";
+ break;
case ID_IPV4_ADDR:
type = "ipv4";
break;
@@ -114,9 +117,6 @@ static void write_id(xmlTextWriterPtr writer, char *element, identification_t *i
xmlTextWriterWriteFormatString(writer, "%D", id);
break;
}
- case ID_ANY:
- xmlTextWriterWriteAttribute(writer, "type", "any");
- break;
default:
/* TODO: base64 keyid */
xmlTextWriterWriteAttribute(writer, "type", "keyid");
@@ -146,17 +146,15 @@ static void write_address(xmlTextWriterPtr writer, char *element, host_t *host)
}
/**
- * write a childEnd
+ * write networks element
*/
-static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local)
+static void write_networks(xmlTextWriterPtr writer, char *element,
+ linked_list_t *list)
{
iterator_t *iterator;
- linked_list_t *list;
traffic_selector_t *ts;
- xmlTextWriterWriteFormatElement(writer, "spi", "%lx",
- htonl(child->get_spi(child, local)));
- xmlTextWriterStartElement(writer, "networks");
- list = child->get_traffic_selectors(child, local);
+
+ xmlTextWriterStartElement(writer, element);
iterator = list->create_iterator(list, TRUE);
while (iterator->iterate(iterator, (void**)&ts))
{
@@ -171,6 +169,19 @@ static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool loca
}
/**
+ * write a childEnd
+ */
+static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local)
+{
+ linked_list_t *list;
+
+ xmlTextWriterWriteFormatElement(writer, "spi", "%lx",
+ htonl(child->get_spi(child, local)));
+ list = child->get_traffic_selectors(child, local);
+ write_networks(writer, "networks", list);
+}
+
+/**
* write a child_sa_t
*/
static void write_child(xmlTextWriterPtr writer, child_sa_t *child)
@@ -284,6 +295,201 @@ static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer
}
/**
+ * process a configlist query request message
+ */
+static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
+{
+ iterator_t *iterator;
+ peer_cfg_t *peer_cfg;
+
+ /* <configlist> */
+ xmlTextWriterStartElement(writer, "configlist");
+
+ iterator = charon->backends->create_iterator(charon->backends);
+ while (iterator->iterate(iterator, (void**)&peer_cfg))
+ {
+ iterator_t *children;
+ child_cfg_t *child_cfg;
+ ike_cfg_t *ike_cfg;
+ linked_list_t *list;
+
+ if (peer_cfg->get_ike_version(peer_cfg) != 2)
+ { /* only IKEv2 connections yet */
+ continue;
+ }
+
+ /* <peerconfig> */
+ xmlTextWriterStartElement(writer, "peerconfig");
+ xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg));
+ write_id(writer, "local", peer_cfg->get_my_id(peer_cfg));
+ write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg));
+
+ /* <ikeconfig> */
+ ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+ xmlTextWriterStartElement(writer, "ikeconfig");
+ write_address(writer, "local", ike_cfg->get_my_host(ike_cfg));
+ write_address(writer, "remote", ike_cfg->get_other_host(ike_cfg));
+ xmlTextWriterEndElement(writer);
+ /* </ikeconfig> */
+
+ /* <childconfiglist> */
+ xmlTextWriterStartElement(writer, "childconfiglist");
+ children = peer_cfg->create_child_cfg_iterator(peer_cfg);
+ while (children->iterate(children, (void**)&child_cfg))
+ {
+ /* <childconfig> */
+ xmlTextWriterStartElement(writer, "childconfig");
+ xmlTextWriterWriteElement(writer, "name",
+ child_cfg->get_name(child_cfg));
+ list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
+ write_networks(writer, "local", list);
+ list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
+ list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
+ write_networks(writer, "remote", list);
+ list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
+ xmlTextWriterEndElement(writer);
+ /* </childconfig> */
+ }
+ children->destroy(children);
+ /* </childconfiglist> */
+ xmlTextWriterEndElement(writer);
+ /* </peerconfig> */
+ xmlTextWriterEndElement(writer);
+ }
+ iterator->destroy(iterator);
+ /* </configlist> */
+ xmlTextWriterEndElement(writer);
+}
+
+/**
+ * callback which logs to a XML writer
+ */
+static bool xml_callback(xmlTextWriterPtr writer, signal_t signal, level_t level,
+ ike_sa_t* ike_sa, char* format, va_list args)
+{
+ if (level <= 1)
+ {
+ /* <item> */
+ xmlTextWriterStartElement(writer, "item");
+ xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level);
+ xmlTextWriterWriteFormatAttribute(writer, "source", "%N", signal_names, signal);
+ xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", pthread_self());
+ xmlTextWriterWriteVFormatString(writer, format, args);
+ xmlTextWriterEndElement(writer);
+ /* </item> */
+ }
+ return TRUE;
+}
+
+/**
+ * process a *terminate control request message
+ */
+static void request_control_terminate(xmlTextReaderPtr reader,
+ xmlTextWriterPtr writer, bool ike)
+{
+ if (xmlTextReaderRead(reader) &&
+ xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT)
+ {
+ const char *str;
+ u_int32_t id;
+ status_t status;
+
+ str = xmlTextReaderConstValue(reader);
+ if (str == NULL || !(id = atoi(str)))
+ {
+ DBG1(DBG_CFG, "error parsing XML id string");
+ return;
+ }
+ DBG1(DBG_CFG, "terminating %s_SA %d", ike ? "IKE" : "CHILD", id);
+
+ /* <log> */
+ xmlTextWriterStartElement(writer, "log");
+ if (ike)
+ {
+ status = charon->interfaces->terminate_ike(
+ charon->interfaces, id,
+ (interface_manager_cb_t)xml_callback, writer);
+ }
+ else
+ {
+ status = charon->interfaces->terminate_child(
+ charon->interfaces, id,
+ (interface_manager_cb_t)xml_callback, writer);
+ }
+ /* </log> */
+ xmlTextWriterEndElement(writer);
+ xmlTextWriterWriteFormatElement(writer, "status", "%d", status);
+ }
+}
+
+/**
+ * process a *initiate control request message
+ */
+static void request_control_initiate(xmlTextReaderPtr reader,
+ xmlTextWriterPtr writer, bool ike)
+{
+ if (xmlTextReaderRead(reader) &&
+ xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT)
+ {
+ const char *str;
+ status_t status = FAILED;
+ peer_cfg_t *peer;
+ child_cfg_t *child = NULL;
+ iterator_t *iterator;
+
+ str = xmlTextReaderConstValue(reader);
+ if (str == NULL)
+ {
+ DBG1(DBG_CFG, "error parsing XML config name string");
+ return;
+ }
+ DBG1(DBG_CFG, "initiating %s_SA %s", ike ? "IKE" : "CHILD", str);
+
+ /* <log> */
+ xmlTextWriterStartElement(writer, "log");
+ peer = charon->backends->get_peer_cfg_by_name(charon->backends, (char*)str);
+ if (peer)
+ {
+ iterator = peer->create_child_cfg_iterator(peer);
+ if (ike)
+ {
+ if (!iterator->iterate(iterator, (void**)&child))
+ {
+ child = NULL;
+ }
+ child->get_ref(child);
+ }
+ else
+ {
+ while (iterator->iterate(iterator, (void**)&child))
+ {
+ if (streq(child->get_name(child), str))
+ {
+ child->get_ref(child);
+ break;
+ }
+ child = NULL;
+ }
+ }
+ iterator->destroy(iterator);
+ if (child)
+ {
+ status = charon->interfaces->initiate(charon->interfaces,
+ peer, child, (interface_manager_cb_t)xml_callback,
+ writer);
+ }
+ else
+ {
+ peer->destroy(peer);
+ }
+ }
+ /* </log> */
+ xmlTextWriterEndElement(writer);
+ xmlTextWriterWriteFormatElement(writer, "status", "%d", status);
+ }
+}
+
+/**
* process a query request
*/
static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
@@ -299,6 +505,11 @@ static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
request_query_ikesa(reader, writer);
break;
}
+ if (streq(xmlTextReaderConstName(reader), "configlist"))
+ {
+ request_query_config(reader, writer);
+ break;
+ }
}
}
/* </query> */
@@ -306,6 +517,43 @@ static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
}
/**
+ * process a control request
+ */
+static void request_control(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
+{
+ /* <control> */
+ xmlTextWriterStartElement(writer, "control");
+ while (xmlTextReaderRead(reader))
+ {
+ if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
+ {
+ if (streq(xmlTextReaderConstName(reader), "ikesaterminate"))
+ {
+ request_control_terminate(reader, writer, TRUE);
+ break;
+ }
+ if (streq(xmlTextReaderConstName(reader), "childsaterminate"))
+ {
+ request_control_terminate(reader, writer, FALSE);
+ break;
+ }
+ if (streq(xmlTextReaderConstName(reader), "ikesainitiate"))
+ {
+ request_control_initiate(reader, writer, TRUE);
+ break;
+ }
+ if (streq(xmlTextReaderConstName(reader), "childsainitiate"))
+ {
+ request_control_initiate(reader, writer, FALSE);
+ break;
+ }
+ }
+ }
+ /* </control> */
+ xmlTextWriterEndElement(writer);
+}
+
+/**
* process a request message
*/
static void request(xmlTextReaderPtr reader, char *id, int fd)
@@ -337,6 +585,11 @@ static void request(xmlTextReaderPtr reader, char *id, int fd)
request_query(reader, writer);
break;
}
+ if (streq(xmlTextReaderConstName(reader), "control"))
+ {
+ request_control(reader, writer);
+ break;
+ }
}
}
/* </message> and close document */
diff --git a/src/charon/daemon.c b/src/charon/daemon.c
index 9e151c305..ee9710424 100644
--- a/src/charon/daemon.c
+++ b/src/charon/daemon.c
@@ -338,7 +338,7 @@ static bool initialize(private_daemon_t *this, bool syslog, level_t levels[])
this->public.interfaces = interface_manager_create();
this->public.backends = backend_manager_create();
this->public.kernel_interface = kernel_interface_create();
- this->public.socket = socket_create(IKEV2_UDP_PORT, IKEV2_NATT_PORT);
+ this->public.socket = socket_create();
this->public.sender = sender_create();
this->public.receiver = receiver_create();
diff --git a/src/charon/encoding/payloads/configuration_attribute.c b/src/charon/encoding/payloads/configuration_attribute.c
index 0aa82169f..afd08c6be 100644
--- a/src/charon/encoding/payloads/configuration_attribute.c
+++ b/src/charon/encoding/payloads/configuration_attribute.c
@@ -165,7 +165,7 @@ static status_t verify(private_configuration_attribute_t *this)
default:
DBG1(DBG_ENC, "unknown attribute type %N",
configuration_attribute_type_names, this->attribute_type);
- return FAILED;
+ break;
}
if (failed)
diff --git a/src/charon/encoding/payloads/eap_payload.c b/src/charon/encoding/payloads/eap_payload.c
index 79ab32fe5..345114af0 100644
--- a/src/charon/encoding/payloads/eap_payload.c
+++ b/src/charon/encoding/payloads/eap_payload.c
@@ -235,11 +235,23 @@ static u_int8_t get_identifier(private_eap_payload_t *this)
/**
* Implementation of eap_payload_t.get_type.
*/
-static eap_type_t get_type(private_eap_payload_t *this)
+static eap_type_t get_type(private_eap_payload_t *this, u_int32_t *vendor)
{
+ eap_type_t type;
+
+ *vendor = 0;
if (this->data.len > 4)
{
- return *(this->data.ptr + 4);
+ type = *(this->data.ptr + 4);
+ if (type != EAP_EXPANDED)
+ {
+ return type;
+ }
+ if (this->data.len >= 12)
+ {
+ *vendor = ntohl(*(u_int32_t*)(this->data.ptr + 4)) & 0x00FFFFFF;
+ return ntohl(*(u_int32_t*)(this->data.ptr + 8));
+ }
}
return 0;
}
@@ -275,7 +287,7 @@ eap_payload_t *eap_payload_create()
this->public.set_data = (void (*) (eap_payload_t *,chunk_t))set_data;
this->public.get_code = (eap_code_t (*) (eap_payload_t*))get_code;
this->public.get_identifier = (u_int8_t (*) (eap_payload_t*))get_identifier;
- this->public.get_type = (eap_type_t (*) (eap_payload_t*))get_type;
+ this->public.get_type = (eap_type_t (*) (eap_payload_t*,u_int32_t*))get_type;
/* private variables */
this->critical = FALSE;
@@ -329,3 +341,4 @@ eap_payload_t *eap_payload_create_nak()
this->set_data(this, data);
return this;
}
+
diff --git a/src/charon/encoding/payloads/eap_payload.h b/src/charon/encoding/payloads/eap_payload.h
index 13c0ade80..3addbb838 100644
--- a/src/charon/encoding/payloads/eap_payload.h
+++ b/src/charon/encoding/payloads/eap_payload.h
@@ -95,9 +95,10 @@ struct eap_payload_t {
* @brief Get the EAP method type.
*
* @param this calling eap_payload_t object
- * @return EAP method type
+ * @param vendor pointer receiving vendor identifier
+ * @return EAP method type, vendor specific if vendor != 0
*/
- eap_type_t (*get_type) (eap_payload_t *this);
+ eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor);
/**
* @brief Destroys an eap_payload_t object.
diff --git a/src/charon/encoding/payloads/endpoint_notify.c b/src/charon/encoding/payloads/endpoint_notify.c
index 30f3ecd5f..98bfb2ea0 100644
--- a/src/charon/encoding/payloads/endpoint_notify.c
+++ b/src/charon/encoding/payloads/endpoint_notify.c
@@ -76,6 +76,13 @@ struct private_endpoint_notify_t {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
+ENUM(p2p_endpoint_type_names, HOST, RELAYED,
+ "HOST",
+ "SERVER_REFLEXIVE",
+ "PEER_REFLEXIVE",
+ "RELAYED"
+);
+
/**
* Helper functions to parse integer values
*/
@@ -152,14 +159,10 @@ static status_t parse_notification_data(private_endpoint_notify_t *this, chunk_t
switch(this->family)
{
- case NO_FAMILY:
- this->endpoint = NULL;
- break;
-
case IPv6:
addr_family = AF_INET6;
addr.len = 16;
- // fall-through
+ /* fall-through */
case IPv4:
if (parse_uint16(&cur, top, &port) != SUCCESS)
{
@@ -177,8 +180,11 @@ static status_t parse_notification_data(private_endpoint_notify_t *this, chunk_t
this->endpoint = host_create_from_chunk(addr_family, addr, port);
break;
+ case NO_FAMILY:
+ default:
+ this->endpoint = NULL;
+ break;
}
-
return SUCCESS;
}
@@ -213,7 +219,7 @@ static chunk_t build_notification_data(private_endpoint_notify_t *this)
}
port_chunk = chunk_from_thing(port);
- // data = prio | family | type | port | addr
+ /* data = prio | family | type | port | addr */
data = chunk_cat("ccccc", prio_chunk, family_chunk, type_chunk,
port_chunk, addr_chunk);
DBG3(DBG_IKE, "p2p_endpoint_data %B", &data);
@@ -251,7 +257,7 @@ static u_int32_t get_priority(private_endpoint_notify_t *this)
*/
static void set_priority(private_endpoint_notify_t *this, u_int32_t priority)
{
- return this->priority = priority;
+ this->priority = priority;
}
/**
@@ -368,13 +374,15 @@ endpoint_notify_t *endpoint_notify_create_from_host(p2p_endpoint_type_t type, ho
this->priority = pow(2, 16) * P2P_PRIO_PEER;
break;
case RELAYED:
+ default:
this->priority = pow(2, 16) * P2P_PRIO_RELAY;
break;
}
this->priority += 65535;
- if (!host) {
+ if (!host)
+ {
return &this->public;
}
@@ -387,7 +395,8 @@ endpoint_notify_t *endpoint_notify_create_from_host(p2p_endpoint_type_t type, ho
this->family = IPv6;
break;
default:
- // unsupported family type, we do not set the hsot (family is set to NO_FAMILY)
+ /* unsupported family type, we do not set the hsot
+ * (family is set to NO_FAMILY) */
return &this->public;
}
diff --git a/src/charon/encoding/payloads/endpoint_notify.h b/src/charon/encoding/payloads/endpoint_notify.h
index 272301d5b..4a3a68f95 100644
--- a/src/charon/encoding/payloads/endpoint_notify.h
+++ b/src/charon/encoding/payloads/endpoint_notify.h
@@ -35,6 +35,11 @@ typedef struct endpoint_notify_t endpoint_notify_t;
#include <encoding/payloads/notify_payload.h>
+/**
+ * @brief P2P endpoint families.
+ *
+ * @ingroup payloads
+ */
enum p2p_endpoint_family_t {
NO_FAMILY = 0,
@@ -47,6 +52,11 @@ enum p2p_endpoint_family_t {
};
+/**
+ * @brief P2P endpoint types.
+ *
+ * @ingroup payloads
+ */
enum p2p_endpoint_type_t {
NO_TYPE = 0,
@@ -64,6 +74,13 @@ enum p2p_endpoint_type_t {
};
/**
+ * enum name for p2p_endpoint_type_t.
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *p2p_endpoint_type_names;
+
+/**
* @brief Class representing a P2P_ENDPOINT notify. In fact it's not
* the notify per se, but the notification data of that notify that is
* handled with this class.
diff --git a/src/charon/encoding/payloads/ike_header.c b/src/charon/encoding/payloads/ike_header.c
index 7253e4f51..3a171b095 100644
--- a/src/charon/encoding/payloads/ike_header.c
+++ b/src/charon/encoding/payloads/ike_header.c
@@ -192,7 +192,8 @@ static status_t verify(private_ike_header_t *this)
if (this->initiator_spi == 0
#ifdef P2P
- // we allow zero spi for INFORMATIONAL exchanges, to allow P2P connectivity checks
+ /* we allow zero spi for INFORMATIONAL exchanges,
+ * to allow P2P connectivity checks */
&& this->exchange_type != INFORMATIONAL
#endif /* P2P */
)
diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c
index 74a6c3197..d32257af6 100644
--- a/src/charon/encoding/payloads/notify_payload.c
+++ b/src/charon/encoding/payloads/notify_payload.c
@@ -57,13 +57,9 @@ ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTH
"INVALID_SELECTORS",
"UNACCEPTABLE_ADDRESSES",
"UNEXPECTED_NAT_DETECTED");
-#ifdef P2P
ENUM_NEXT(notify_type_names, P2P_CONNECT_FAILED, P2P_CONNECT_FAILED, UNEXPECTED_NAT_DETECTED,
"P2P_CONNECT_FAILED");
ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, P2P_CONNECT_FAILED,
-#else
-ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED,
-#endif /* P2P */
"INITIAL_CONTACT",
"SET_WINDOW_SIZE",
"ADDITIONAL_TS_POSSIBLE",
@@ -86,7 +82,6 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETE
"AUTH_LIFETIME");
ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME,
"EAP_ONLY_AUTHENTICATION");
-#ifdef P2P
ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION,
"USE_BEET_MODE");
ENUM_NEXT(notify_type_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE,
@@ -97,9 +92,6 @@ ENUM_NEXT(notify_type_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE,
"P2P_SESSIONKEY",
"P2P_RESPONSE");
ENUM_END(notify_type_names, P2P_RESPONSE);
-#else
-ENUM_END(notify_type_names, EAP_ONLY_AUTHENTICATION);
-#endif /* P2P */
ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
@@ -128,13 +120,9 @@ ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED
"INVAL_SEL",
"UNACCEPT_ADDR",
"UNEXPECT_NAT");
-#ifdef P2P
ENUM_NEXT(notify_type_short_names, P2P_CONNECT_FAILED, P2P_CONNECT_FAILED, UNEXPECTED_NAT_DETECTED,
"P2P_CONN_FAIL");
ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, P2P_CONNECT_FAILED,
-#else
-ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED,
-#endif /* P2P */
"INIT_CONTACT",
"SET_WINSIZE",
"ADD_TS_POSS",
@@ -157,7 +145,6 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NA
"AUTH_LFT");
ENUM_NEXT(notify_type_short_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME,
"EAP_ONLY");
-#ifdef P2P
ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION,
"BEET_MODE");
ENUM_NEXT(notify_type_short_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE,
@@ -168,9 +155,6 @@ ENUM_NEXT(notify_type_short_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE,
"P2P_SKEY",
"P2P_R");
ENUM_END(notify_type_short_names, P2P_RESPONSE);
-#else
-ENUM_END(notify_type_short_names, EAP_ONLY_AUTHENTICATION);
-#endif /* P2P */
typedef struct private_notify_payload_t private_notify_payload_t;
@@ -342,7 +326,15 @@ static status_t verify(private_notify_payload_t *this)
}
break;
}
- // FIXME: check size of P2P-NAT-T payloads
+ case AUTH_LIFETIME:
+ {
+ if (this->notification_data.len != 4)
+ {
+ bad_length = TRUE;
+ }
+ break;
+ }
+ /* FIXME: check size of P2P-NAT-T payloads */
default:
/* TODO: verify */
break;
diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h
index 4a9ad992b..03f61d473 100644
--- a/src/charon/encoding/payloads/notify_payload.h
+++ b/src/charon/encoding/payloads/notify_payload.h
@@ -68,10 +68,9 @@ enum notify_type_t {
INVALID_SELECTORS = 39,
UNACCEPTABLE_ADDRESSES = 40,
UNEXPECTED_NAT_DETECTED = 41,
-#ifdef P2P
/* P2P-NAT-T, private use */
P2P_CONNECT_FAILED = 8192,
-#endif /* P2P */
+
/* notify status messages */
INITIAL_CONTACT = 16384,
SET_WINDOW_SIZE = 16385,
@@ -99,7 +98,6 @@ enum notify_type_t {
EAP_ONLY_AUTHENTICATION = 40960,
/* BEET mode, not even a draft yet. private use */
USE_BEET_MODE = 40961,
-#ifdef P2P
/* P2P-NAT-T, private use */
P2P_MEDIATION = 40962,
P2P_ENDPOINT = 40963,
@@ -107,7 +105,6 @@ enum notify_type_t {
P2P_SESSIONID = 40965,
P2P_SESSIONKEY = 40966,
P2P_RESPONSE = 40967
-#endif /* P2P */
};
/**
diff --git a/src/charon/network/socket-raw.c b/src/charon/network/socket-raw.c
new file mode 100644
index 000000000..3b76ae570
--- /dev/null
+++ b/src/charon/network/socket-raw.c
@@ -0,0 +1,771 @@
+/**
+ * @file socket.c
+ *
+ * @brief Implementation of socket_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * 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 <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <linux/ipsec.h>
+#include <linux/filter.h>
+#include <net/if.h>
+
+#include "socket.h"
+
+#include <daemon.h>
+
+/* constants for packet handling */
+#define IP_LEN sizeof(struct iphdr)
+#define IP6_LEN sizeof(struct ip6_hdr)
+#define UDP_LEN sizeof(struct udphdr)
+#define MARKER_LEN sizeof(u_int32_t)
+
+/* offsets for packet handling */
+#define IP_PROTO_OFFSET 9
+#define IP6_PROTO_OFFSET 6
+#define IKE_VERSION_OFFSET 17
+#define IKE_LENGTH_OFFSET 24
+
+/* from linux/in.h */
+#ifndef IP_IPSEC_POLICY
+#define IP_IPSEC_POLICY 16
+#endif /*IP_IPSEC_POLICY*/
+
+/* from linux/udp.h */
+#ifndef UDP_ENCAP
+#define UDP_ENCAP 100
+#endif /*UDP_ENCAP*/
+
+#ifndef UDP_ENCAP_ESPINUDP
+#define UDP_ENCAP_ESPINUDP 2
+#endif /*UDP_ENCAP_ESPINUDP*/
+
+/* needed for older kernel headers */
+#ifndef IPV6_2292PKTINFO
+#define IPV6_2292PKTINFO 2
+#endif /*IPV6_2292PKTINFO*/
+
+/* missing on uclibc */
+#ifndef IPV6_IPSEC_POLICY
+#define IPV6_IPSEC_POLICY 34
+#endif /*IPV6_IPSEC_POLICY*/
+
+typedef struct private_socket_t private_socket_t;
+
+/**
+ * Private data of an socket_t object
+ */
+struct private_socket_t{
+ /**
+ * public functions
+ */
+ socket_t public;
+
+ /**
+ * regular port
+ */
+ int port;
+
+ /**
+ * port used for nat-t
+ */
+ int natt_port;
+
+ /**
+ * raw receiver socket for IPv4
+ */
+ int recv4;
+
+ /**
+ * raw receiver socket for IPv6
+ */
+ int recv6;
+
+ /**
+ * send socket on regular port for IPv4
+ */
+ int send4;
+
+ /**
+ * send socket on regular port for IPv6
+ */
+ int send6;
+
+ /**
+ * send socket on nat-t port for IPv4
+ */
+ int send4_natt;
+
+ /**
+ * send socket on nat-t port for IPv6
+ */
+ int send6_natt;
+};
+
+/**
+ * implementation of socket_t.receive
+ */
+static status_t receiver(private_socket_t *this, packet_t **packet)
+{
+ char buffer[MAX_PACKET];
+ chunk_t data;
+ packet_t *pkt;
+ struct udphdr *udp;
+ host_t *source = NULL, *dest = NULL;
+ int bytes_read = 0;
+ int data_offset, oldstate;
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+
+ if (this->recv4)
+ {
+ FD_SET(this->recv4, &rfds);
+ }
+ if (this->recv6)
+ {
+ FD_SET(this->recv6, &rfds);
+ }
+
+ DBG2(DBG_NET, "waiting for data on raw sockets");
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ if (select(max(this->recv4, this->recv6) + 1, &rfds, NULL, NULL, NULL) <= 0)
+ {
+ pthread_setcancelstate(oldstate, NULL);
+ return FAILED;
+ }
+ pthread_setcancelstate(oldstate, NULL);
+
+ if (this->recv4 && FD_ISSET(this->recv4, &rfds))
+ {
+ /* IPv4 raw sockets return the IP header. We read src/dest
+ * information directly from the raw header */
+ struct iphdr *ip;
+ struct sockaddr_in src, dst;
+
+ bytes_read = recv(this->recv4, buffer, MAX_PACKET, 0);
+ if (bytes_read < 0)
+ {
+ DBG1(DBG_NET, "error reading from IPv4 socket: %s", strerror(errno));
+ return FAILED;
+ }
+ DBG3(DBG_NET, "received IPv4 packet %b", buffer, bytes_read);
+
+ /* read source/dest from raw IP/UDP header */
+ if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN)
+ {
+ DBG1(DBG_NET, "received IPv4 packet too short (%d bytes)",
+ bytes_read);
+ return FAILED;
+ }
+ ip = (struct iphdr*) buffer;
+ udp = (struct udphdr*) (buffer + IP_LEN);
+ src.sin_family = AF_INET;
+ src.sin_addr.s_addr = ip->saddr;
+ src.sin_port = udp->source;
+ dst.sin_family = AF_INET;
+ dst.sin_addr.s_addr = ip->daddr;
+ dst.sin_port = udp->dest;
+ source = host_create_from_sockaddr((sockaddr_t*)&src);
+ dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+
+ pkt = packet_create();
+ pkt->set_source(pkt, source);
+ pkt->set_destination(pkt, dest);
+ DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest);
+ data_offset = IP_LEN + UDP_LEN;
+ /* remove non esp marker */
+ if (dest->get_port(dest) == IKEV2_NATT_PORT)
+ {
+ data_offset += MARKER_LEN;
+ }
+ /* fill in packet */
+ data.len = bytes_read - data_offset;
+ data.ptr = malloc(data.len);
+ memcpy(data.ptr, buffer + data_offset, data.len);
+ pkt->set_data(pkt, data);
+ }
+ else if (this->recv6 && FD_ISSET(this->recv6, &rfds))
+ {
+ /* IPv6 raw sockets return no IP header. We must query
+ * src/dest via socket options/ancillary data */
+ struct msghdr msg;
+ struct cmsghdr *cmsgptr;
+ struct sockaddr_in6 src, dst;
+ struct iovec iov;
+ char ancillary[64];
+
+ msg.msg_name = &src;
+ msg.msg_namelen = sizeof(src);
+ iov.iov_base = buffer;
+ iov.iov_len = sizeof(buffer);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = ancillary;
+ msg.msg_controllen = sizeof(ancillary);
+ msg.msg_flags = 0;
+
+ bytes_read = recvmsg(this->recv6, &msg, 0);
+ if (bytes_read < 0)
+ {
+ DBG1(DBG_NET, "error reading from IPv6 socket: %s", strerror(errno));
+ return FAILED;
+ }
+ DBG3(DBG_NET, "received IPv6 packet %b", buffer, bytes_read);
+
+ if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN)
+ {
+ DBG3(DBG_NET, "received IPv6 packet too short (%d bytes)",
+ bytes_read);
+ return FAILED;
+ }
+
+ /* read ancillary data to get destination address */
+ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+ cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
+ {
+ if (cmsgptr->cmsg_len == 0)
+ {
+ DBG1(DBG_NET, "error reading IPv6 ancillary data");
+ return FAILED;
+ }
+ if (cmsgptr->cmsg_level == SOL_IPV6 &&
+ cmsgptr->cmsg_type == IPV6_2292PKTINFO)
+ {
+ struct in6_pktinfo *pktinfo;
+ pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr);
+
+ memset(&dst, 0, sizeof(dst));
+ memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr));
+ dst.sin6_family = AF_INET6;
+ udp = (struct udphdr*) (buffer);
+ dst.sin6_port = udp->dest;
+ src.sin6_port = udp->source;
+ dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+ }
+ }
+ /* ancillary data missing? */
+ if (dest == NULL)
+ {
+ DBG1(DBG_NET, "error reading IPv6 packet header");
+ return FAILED;
+ }
+
+ source = host_create_from_sockaddr((sockaddr_t*)&src);
+
+ pkt = packet_create();
+ pkt->set_source(pkt, source);
+ pkt->set_destination(pkt, dest);
+ DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest);
+ data_offset = UDP_LEN;
+ /* remove non esp marker */
+ if (dest->get_port(dest) == IKEV2_NATT_PORT)
+ {
+ data_offset += MARKER_LEN;
+ }
+ /* fill in packet */
+ data.len = bytes_read - data_offset;
+ data.ptr = malloc(data.len);
+ memcpy(data.ptr, buffer + data_offset, data.len);
+ pkt->set_data(pkt, data);
+ }
+ else
+ {
+ /* oops, shouldn't happen */
+ return FAILED;
+ }
+
+ /* return packet */
+ *packet = pkt;
+ return SUCCESS;
+}
+
+/**
+ * implementation of socket_t.send
+ */
+status_t sender(private_socket_t *this, packet_t *packet)
+{
+ int sport, skt, family;
+ ssize_t bytes_sent;
+ chunk_t data, marked;
+ host_t *src, *dst;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+
+ src = packet->get_source(packet);
+ dst = packet->get_destination(packet);
+ data = packet->get_data(packet);
+
+ DBG2(DBG_NET, "sending packet: from %#H to %#H", src, dst);
+
+ /* send data */
+ sport = src->get_port(src);
+ family = dst->get_family(dst);
+ if (sport == IKEV2_UDP_PORT)
+ {
+ if (family == AF_INET)
+ {
+ skt = this->send4;
+ }
+ else
+ {
+ skt = this->send6;
+ }
+ }
+ else if (sport == IKEV2_NATT_PORT)
+ {
+ if (family == AF_INET)
+ {
+ skt = this->send4_natt;
+ }
+ else
+ {
+ skt = this->send6_natt;
+ }
+ /* NAT keepalives without marker */
+ if (data.len != 1 || data.ptr[0] != 0xFF)
+ {
+ /* add non esp marker to packet */
+ if (data.len > MAX_PACKET - MARKER_LEN)
+ {
+ DBG1(DBG_NET, "unable to send packet: it's too big (%d bytes)",
+ data.len);
+ return FAILED;
+ }
+ marked = chunk_alloc(data.len + MARKER_LEN);
+ memset(marked.ptr, 0, MARKER_LEN);
+ memcpy(marked.ptr + MARKER_LEN, data.ptr, data.len);
+ /* let the packet do the clean up for us */
+ packet->set_data(packet, marked);
+ data = marked;
+ }
+ }
+ else
+ {
+ DBG1(DBG_NET, "unable to locate a send socket for port %d", sport);
+ return FAILED;
+ }
+
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = dst->get_sockaddr(dst);;
+ msg.msg_namelen = *dst->get_sockaddr_len(dst);
+ iov.iov_base = data.ptr;
+ iov.iov_len = data.len;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+
+ if (!dst->is_anyaddr(dst))
+ {
+ if (family == AF_INET)
+ {
+ char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
+ struct in_pktinfo *pktinfo;
+ struct sockaddr_in *sin;
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ memset(pktinfo, 0, sizeof(struct in_pktinfo));
+ sin = (struct sockaddr_in*)src->get_sockaddr(src);
+ memcpy(&pktinfo->ipi_spec_dst, &sin->sin_addr, sizeof(struct in_addr));
+ }
+ else
+ {
+ char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+ struct in6_pktinfo *pktinfo;
+ struct sockaddr_in6 *sin;
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_IPV6;
+ cmsg->cmsg_type = IPV6_2292PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ memset(pktinfo, 0, sizeof(struct in6_pktinfo));
+ sin = (struct sockaddr_in6*)src->get_sockaddr(src);
+ memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
+ }
+ }
+
+ bytes_sent = sendmsg(skt, &msg, 0);
+
+ if (bytes_sent != data.len)
+ {
+ DBG1(DBG_NET, "error writing to socket: %s", strerror(errno));
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * open a socket to send packets
+ */
+static int open_send_socket(private_socket_t *this, int family, u_int16_t port)
+{
+ int on = TRUE;
+ int type = UDP_ENCAP_ESPINUDP;
+ struct sockaddr_storage addr;
+ u_int sol, ipsec_policy;
+ struct sadb_x_policy policy;
+ int skt;
+
+ memset(&addr, 0, sizeof(addr));
+ /* precalculate constants depending on address family */
+ switch (family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = INADDR_ANY;
+ sin->sin_port = htons(port);
+ sol = SOL_IP;
+ ipsec_policy = IP_IPSEC_POLICY;
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
+ sin6->sin6_port = htons(port);
+ sol = SOL_IPV6;
+ ipsec_policy = IPV6_IPSEC_POLICY;
+ break;
+ }
+ default:
+ return 0;
+ }
+
+ skt = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+ if (skt < 0)
+ {
+ DBG1(DBG_NET, "could not open send socket: %s", strerror(errno));
+ return 0;
+ }
+
+ if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set SO_REUSEADDR on send socket: %s",
+ strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ /* bypass outgoung IKE traffic on send socket */
+ memset(&policy, 0, sizeof(policy));
+ policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
+ policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
+ policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
+
+ if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %s",
+ strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ /* We don't receive packets on the send socket, but we need a INBOUND policy.
+ * Otherwise, UDP decapsulation does not work!!! */
+ policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+ if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %s",
+ strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ /* bind the send socket */
+ if (bind(skt, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ {
+ DBG1(DBG_NET, "unable to bind send socket: %s",
+ strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ if (family == AF_INET)
+ {
+ /* enable UDP decapsulation globally, only for one socket needed */
+ if (setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set UDP_ENCAP: %s; NAT-T may fail",
+ strerror(errno));
+ }
+ }
+
+ return skt;
+}
+
+/**
+ * open a socket to receive packets
+ */
+static int open_recv_socket(private_socket_t *this, int family)
+{
+ int skt;
+ int on = TRUE;
+ u_int proto_offset, ip_len, sol, ipsec_policy, udp_header, ike_header;
+ struct sadb_x_policy policy;
+
+ /* precalculate constants depending on address family */
+ switch (family)
+ {
+ case AF_INET:
+ proto_offset = IP_PROTO_OFFSET;
+ ip_len = IP_LEN;
+ sol = SOL_IP;
+ ipsec_policy = IP_IPSEC_POLICY;
+ break;
+ case AF_INET6:
+ proto_offset = IP6_PROTO_OFFSET;
+ ip_len = 0; /* IPv6 raw sockets contain no IP header */
+ sol = SOL_IPV6;
+ ipsec_policy = IPV6_IPSEC_POLICY;
+ break;
+ default:
+ return 0;
+ }
+ udp_header = ip_len;
+ ike_header = ip_len + UDP_LEN;
+
+ /* This filter code filters out all non-IKEv2 traffic on
+ * a SOCK_RAW IP_PROTP_UDP socket. Handling of other
+ * IKE versions is done in pluto.
+ */
+ struct sock_filter ikev2_filter_code[] =
+ {
+ /* 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),
+ /* port */
+ /* IKE version must be 2.0 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + IKE_VERSION_OFFSET),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10),
+ /* 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),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ /* 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_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),
+ /* 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),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ /* packet doesn't match, ignore */
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ /* Filter struct to use with setsockopt */
+ struct sock_fprog ikev2_filter = {
+ sizeof(ikev2_filter_code) / sizeof(struct sock_filter),
+ ikev2_filter_code
+ };
+
+ /* set up a raw socket */
+ skt = socket(family, SOCK_RAW, IPPROTO_UDP);
+ if (skt < 0)
+ {
+ DBG1(DBG_NET, "unable to create raw socket: %s", strerror(errno));
+ return 0;
+ }
+
+ if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER,
+ &ikev2_filter, sizeof(ikev2_filter)) < 0)
+ {
+ DBG1(DBG_NET, "unable to attach IKEv2 filter to raw socket: %s",
+ strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ if (family == AF_INET6 &&
+ /* we use IPV6_2292PKTINFO, as IPV6_PKTINFO is defined as
+ * 2 or 50 depending on kernel header version */
+ setsockopt(skt, sol, IPV6_2292PKTINFO, &on, sizeof(on)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set IPV6_PKTINFO on raw socket: %s",
+ strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ /* bypass incomining IKE traffic on this socket */
+ memset(&policy, 0, sizeof(policy));
+ policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
+ policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
+ policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+
+ if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set IPSEC_POLICY on raw socket: %s",
+ strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ return skt;
+}
+
+/**
+ * implementation of socket_t.destroy
+ */
+static void destroy(private_socket_t *this)
+{
+ if (this->recv4)
+ {
+ close(this->recv4);
+ }
+ if (this->recv6)
+ {
+ close(this->recv6);
+ }
+ if (this->send4)
+ {
+ close(this->send4);
+ }
+ if (this->send6)
+ {
+ close(this->send6);
+ }
+ if (this->send4_natt)
+ {
+ close(this->send4_natt);
+ }
+ if (this->send6_natt)
+ {
+ close(this->send6_natt);
+ }
+ free(this);
+}
+
+/*
+ * See header for description
+ */
+socket_t *socket_create()
+{
+ int key;
+ private_socket_t *this = malloc_thing(private_socket_t);
+
+ /* public functions */
+ this->public.send = (status_t(*)(socket_t*, packet_t*))sender;
+ this->public.receive = (status_t(*)(socket_t*, packet_t**))receiver;
+ this->public.destroy = (void(*)(socket_t*)) destroy;
+
+ this->recv4 = 0;
+ this->recv6 = 0;
+ this->send4 = 0;
+ this->send6 = 0;
+ this->send4_natt = 0;
+ this->send6_natt = 0;
+
+ /* we open a AF_KEY socket to autoload the af_key module. Otherwise
+ * setsockopt(IPSEC_POLICY) won't work. */
+ key = socket(AF_KEY, SOCK_RAW, PF_KEY_V2);
+ if (key == 0)
+ {
+ charon->kill(charon, "could not open AF_KEY socket");
+ }
+ close(key);
+
+ this->recv4 = open_recv_socket(this, AF_INET);
+ if (this->recv4 == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv4 receive socket, IPv4 disabled");
+ }
+ else
+ {
+ this->send4 = open_send_socket(this, AF_INET, IKEV2_UDP_PORT);
+ if (this->send4 == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv4 send socket, IPv4 disabled");
+ close(this->recv4);
+ }
+ else
+ {
+ this->send4_natt = open_send_socket(this, AF_INET, IKEV2_NATT_PORT);
+ if (this->send4_natt == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv4 NAT-T send socket");
+ }
+ }
+ }
+
+ this->recv6 = open_recv_socket(this, AF_INET6);
+ if (this->recv6 == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv6 receive socket, IPv6 disabled");
+ }
+ else
+ {
+ this->send6 = open_send_socket(this, AF_INET6, IKEV2_UDP_PORT);
+ if (this->send6 == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv6 send socket, IPv6 disabled");
+ close(this->recv6);
+ }
+ else
+ {
+ this->send6_natt = open_send_socket(this, AF_INET6, IKEV2_NATT_PORT);
+ if (this->send6_natt == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv6 NAT-T send socket");
+ }
+ }
+ }
+
+ if (!(this->send4 || this->send6) || !(this->recv4 || this->recv6))
+ {
+ DBG1(DBG_NET, "could not create any sockets");
+ destroy(this);
+ charon->kill(charon, "socket initialization failed");
+ }
+
+ return (socket_t*)this;
+}
diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c
index dd231ebed..a4c407579 100644
--- a/src/charon/network/socket.c
+++ b/src/charon/network/socket.c
@@ -7,7 +7,7 @@
/*
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -43,18 +43,9 @@
#include <daemon.h>
-/* constants for packet handling */
-#define IP_LEN sizeof(struct iphdr)
-#define IP6_LEN sizeof(struct ip6_hdr)
-#define UDP_LEN sizeof(struct udphdr)
+/* length of non-esp marker */
#define MARKER_LEN sizeof(u_int32_t)
-/* offsets for packet handling */
-#define IP_PROTO_OFFSET 9
-#define IP6_PROTO_OFFSET 6
-#define IKE_VERSION_OFFSET 17
-#define IKE_LENGTH_OFFSET 24
-
/* from linux/in.h */
#ifndef IP_IPSEC_POLICY
#define IP_IPSEC_POLICY 16
@@ -84,51 +75,31 @@ typedef struct private_socket_t private_socket_t;
/**
* Private data of an socket_t object
*/
-struct private_socket_t{
+struct private_socket_t {
/**
* public functions
*/
socket_t public;
-
- /**
- * regular port
- */
- int port;
-
- /**
- * port used for nat-t
- */
- int natt_port;
/**
- * raw receiver socket for IPv4
+ * IPv4 socket (500)
*/
- int recv4;
+ int ipv4;
/**
- * raw receiver socket for IPv6
- */
- int recv6;
-
- /**
- * send socket on regular port for IPv4
+ * IPv4 socket for NATT (4500)
*/
- int send4;
-
- /**
- * send socket on regular port for IPv6
- */
- int send6;
-
+ int ipv4_natt;
+
/**
- * send socket on nat-t port for IPv4
+ * IPv6 socket (500)
*/
- int send4_natt;
-
+ int ipv6;
+
/**
- * send socket on nat-t port for IPv6
+ * IPv6 socket for NATT (4500)
*/
- int send6_natt;
+ int ipv6_natt;
};
/**
@@ -139,91 +110,72 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
char buffer[MAX_PACKET];
chunk_t data;
packet_t *pkt;
- struct udphdr *udp;
host_t *source = NULL, *dest = NULL;
int bytes_read = 0;
int data_offset, oldstate;
fd_set rfds;
+ int max_fd = 0, selected = 0;
+ u_int16_t port;
FD_ZERO(&rfds);
- if (this->recv4)
+ if (this->ipv4)
{
- FD_SET(this->recv4, &rfds);
+ FD_SET(this->ipv4, &rfds);
}
- if (this->recv6)
+ if (this->ipv4_natt)
{
- FD_SET(this->recv6, &rfds);
+ FD_SET(this->ipv4_natt, &rfds);
}
+ if (this->ipv6)
+ {
+ FD_SET(this->ipv6, &rfds);
+ }
+ if (this->ipv6_natt)
+ {
+ FD_SET(this->ipv6_natt, &rfds);
+ }
+ max_fd = max(max(this->ipv4, this->ipv4_natt), max(this->ipv6, this->ipv6_natt));
- DBG2(DBG_NET, "waiting for data on raw sockets");
-
+ DBG2(DBG_NET, "waiting for data on sockets");
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
- if (select(max(this->recv4, this->recv6) + 1, &rfds, NULL, NULL, NULL) <= 0)
+ if (select(max_fd + 1, &rfds, NULL, NULL, NULL) <= 0)
{
pthread_setcancelstate(oldstate, NULL);
return FAILED;
}
pthread_setcancelstate(oldstate, NULL);
- if (this->recv4 && FD_ISSET(this->recv4, &rfds))
+ if (FD_ISSET(this->ipv4, &rfds))
{
- /* IPv4 raw sockets return the IP header. We read src/dest
- * information directly from the raw header */
- struct iphdr *ip;
- struct sockaddr_in src, dst;
-
- bytes_read = recv(this->recv4, buffer, MAX_PACKET, 0);
- if (bytes_read < 0)
- {
- DBG1(DBG_NET, "error reading from IPv4 socket: %s", strerror(errno));
- return FAILED;
- }
- DBG3(DBG_NET, "received IPv4 packet %b", buffer, bytes_read);
-
- /* read source/dest from raw IP/UDP header */
- if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN)
- {
- DBG1(DBG_NET, "received IPv4 packet too short (%d bytes)",
- bytes_read);
- return FAILED;
- }
- ip = (struct iphdr*) buffer;
- udp = (struct udphdr*) (buffer + IP_LEN);
- src.sin_family = AF_INET;
- src.sin_addr.s_addr = ip->saddr;
- src.sin_port = udp->source;
- dst.sin_family = AF_INET;
- dst.sin_addr.s_addr = ip->daddr;
- dst.sin_port = udp->dest;
- source = host_create_from_sockaddr((sockaddr_t*)&src);
- dest = host_create_from_sockaddr((sockaddr_t*)&dst);
-
- pkt = packet_create();
- pkt->set_source(pkt, source);
- pkt->set_destination(pkt, dest);
- DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest);
- data_offset = IP_LEN + UDP_LEN;
- /* remove non esp marker */
- if (dest->get_port(dest) == this->natt_port)
- {
- data_offset += MARKER_LEN;
- }
- /* fill in packet */
- data.len = bytes_read - data_offset;
- data.ptr = malloc(data.len);
- memcpy(data.ptr, buffer + data_offset, data.len);
- pkt->set_data(pkt, data);
+ port = IKEV2_UDP_PORT;
+ selected = this->ipv4;
}
- else if (this->recv6 && FD_ISSET(this->recv6, &rfds))
+ if (FD_ISSET(this->ipv4_natt, &rfds))
+ {
+ port = IKEV2_NATT_PORT;
+ selected = this->ipv4_natt;
+ }
+ if (FD_ISSET(this->ipv6, &rfds))
+ {
+ port = IKEV2_UDP_PORT;
+ selected = this->ipv6;
+ }
+ if (FD_ISSET(this->ipv6_natt, &rfds))
+ {
+ port = IKEV2_NATT_PORT;
+ selected = this->ipv6_natt;
+ }
+ if (selected)
{
- /* IPv6 raw sockets return no IP header. We must query
- * src/dest via socket options/ancillary data */
struct msghdr msg;
struct cmsghdr *cmsgptr;
- struct sockaddr_in6 src, dst;
struct iovec iov;
char ancillary[64];
+ union {
+ struct sockaddr_in in4;
+ struct sockaddr_in6 in6;
+ } src;
msg.msg_name = &src;
msg.msg_namelen = sizeof(src);
@@ -234,18 +186,17 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
msg.msg_control = ancillary;
msg.msg_controllen = sizeof(ancillary);
msg.msg_flags = 0;
-
- bytes_read = recvmsg(this->recv6, &msg, 0);
+ bytes_read = recvmsg(selected, &msg, 0);
if (bytes_read < 0)
{
- DBG1(DBG_NET, "error reading from IPv6 socket: %s", strerror(errno));
+ DBG1(DBG_NET, "error reading socket: %s", strerror(errno));
return FAILED;
}
- DBG3(DBG_NET, "received IPv6 packet %b", buffer, bytes_read);
+ DBG3(DBG_NET, "received packet %b", buffer, bytes_read);
- if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN)
+ if (bytes_read < MARKER_LEN)
{
- DBG3(DBG_NET, "received IPv6 packet too short (%d bytes)",
+ DBG3(DBG_NET, "received packet too short (%d bytes)",
bytes_read);
return FAILED;
}
@@ -256,40 +207,55 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
{
if (cmsgptr->cmsg_len == 0)
{
- DBG1(DBG_NET, "error reading IPv6 ancillary data");
+ DBG1(DBG_NET, "error reading ancillary data");
return FAILED;
- }
+ }
+
if (cmsgptr->cmsg_level == SOL_IPV6 &&
cmsgptr->cmsg_type == IPV6_2292PKTINFO)
{
struct in6_pktinfo *pktinfo;
pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr);
+ struct sockaddr_in6 dst;
memset(&dst, 0, sizeof(dst));
memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr));
dst.sin6_family = AF_INET6;
- udp = (struct udphdr*) (buffer);
- dst.sin6_port = udp->dest;
- src.sin6_port = udp->source;
+ dst.sin6_port = htons(port);
dest = host_create_from_sockaddr((sockaddr_t*)&dst);
}
+ if (cmsgptr->cmsg_level == SOL_IP &&
+ cmsgptr->cmsg_type == IP_PKTINFO)
+ {
+ struct in_pktinfo *pktinfo;
+ pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsgptr);
+ struct sockaddr_in dst;
+
+ memset(&dst, 0, sizeof(dst));
+ memcpy(&dst.sin_addr, &pktinfo->ipi_addr, sizeof(dst.sin_addr));
+ dst.sin_family = AF_INET;
+ dst.sin_port = htons(port);
+ dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+ }
+ if (dest)
+ {
+ break;
+ }
}
- /* ancillary data missing? */
if (dest == NULL)
{
- DBG1(DBG_NET, "error reading IPv6 packet header");
+ DBG1(DBG_NET, "error reading IP header");
return FAILED;
}
-
source = host_create_from_sockaddr((sockaddr_t*)&src);
pkt = packet_create();
pkt->set_source(pkt, source);
pkt->set_destination(pkt, dest);
DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest);
- data_offset = UDP_LEN;
+ data_offset = 0;
/* remove non esp marker */
- if (dest->get_port(dest) == this->natt_port)
+ if (dest->get_port(dest) == IKEV2_NATT_PORT)
{
data_offset += MARKER_LEN;
}
@@ -304,7 +270,6 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
/* oops, shouldn't happen */
return FAILED;
}
-
/* return packet */
*packet = pkt;
return SUCCESS;
@@ -332,26 +297,26 @@ status_t sender(private_socket_t *this, packet_t *packet)
/* send data */
sport = src->get_port(src);
family = dst->get_family(dst);
- if (sport == this->port)
+ if (sport == IKEV2_UDP_PORT)
{
if (family == AF_INET)
{
- skt = this->send4;
+ skt = this->ipv4;
}
else
{
- skt = this->send6;
+ skt = this->ipv6;
}
}
- else if (sport == this->natt_port)
+ else if (sport == IKEV2_NATT_PORT)
{
if (family == AF_INET)
{
- skt = this->send4_natt;
+ skt = this->ipv4_natt;
}
else
{
- skt = this->send6_natt;
+ skt = this->ipv6_natt;
}
/* NAT keepalives without marker */
if (data.len != 1 || data.ptr[0] != 0xFF)
@@ -437,12 +402,12 @@ status_t sender(private_socket_t *this, packet_t *packet)
/**
* open a socket to send packets
*/
-static int open_send_socket(private_socket_t *this, int family, u_int16_t port)
+static int open_socket(private_socket_t *this, int family, u_int16_t port)
{
int on = TRUE;
int type = UDP_ENCAP_ESPINUDP;
struct sockaddr_storage addr;
- u_int sol, ipsec_policy;
+ u_int sol, ipsec_policy, pktinfo;
struct sadb_x_policy policy;
int skt;
@@ -458,6 +423,7 @@ static int open_send_socket(private_socket_t *this, int family, u_int16_t port)
sin->sin_port = htons(port);
sol = SOL_IP;
ipsec_policy = IP_IPSEC_POLICY;
+ pktinfo = IP_PKTINFO;
break;
}
case AF_INET6:
@@ -468,6 +434,7 @@ static int open_send_socket(private_socket_t *this, int family, u_int16_t port)
sin6->sin6_port = htons(port);
sol = SOL_IPV6;
ipsec_policy = IPV6_IPSEC_POLICY;
+ pktinfo = IPV6_2292PKTINFO;
break;
}
default:
@@ -477,39 +444,34 @@ static int open_send_socket(private_socket_t *this, int family, u_int16_t port)
skt = socket(family, SOCK_DGRAM, IPPROTO_UDP);
if (skt < 0)
{
- DBG1(DBG_NET, "could not open send socket: %s", strerror(errno));
+ DBG1(DBG_NET, "could not open socket: %s", strerror(errno));
return 0;
}
-
if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
{
- DBG1(DBG_NET, "unable to set SO_REUSEADDR on send socket: %s",
- strerror(errno));
+ DBG1(DBG_NET, "unable to set SO_REUSEADDR on socket: %s", strerror(errno));
close(skt);
return 0;
}
- /* bypass outgoung IKE traffic on send socket */
+ /* bypass IKE traffic on socket */
memset(&policy, 0, sizeof(policy));
policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
- policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
+ policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
- DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %s",
+ DBG1(DBG_NET, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
close(skt);
return 0;
}
-
- /* We don't receive packets on the send socket, but we need a INBOUND policy.
- * Otherwise, UDP decapsulation does not work!!! */
policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
- DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %s",
+ DBG1(DBG_NET, "unable to set IPSEC_POLICY on socket: %s",
strerror(errno));
close(skt);
return 0;
@@ -518,138 +480,25 @@ static int open_send_socket(private_socket_t *this, int family, u_int16_t port)
/* bind the send socket */
if (bind(skt, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
- DBG1(DBG_NET, "unable to bind send socket: %s",
- strerror(errno));
+ DBG1(DBG_NET, "unable to bind socket: %s", strerror(errno));
close(skt);
return 0;
}
- if (family == AF_INET)
+ /* get additional packet info on receive */
+ if (setsockopt(skt, sol, pktinfo, &on, sizeof(on)) < 0)
{
- /* enable UDP decapsulation globally, only for one socket needed */
- if (setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
- {
- DBG1(DBG_NET, "unable to set UDP_ENCAP: %s; NAT-T may fail",
- strerror(errno));
- }
- }
-
- return skt;
-}
-
-/**
- * open a socket to receive packets
- */
-static int open_recv_socket(private_socket_t *this, int family)
-{
- int skt;
- int on = TRUE;
- u_int proto_offset, ip_len, sol, ipsec_policy, udp_header, ike_header;
- struct sadb_x_policy policy;
-
- /* precalculate constants depending on address family */
- switch (family)
- {
- case AF_INET:
- proto_offset = IP_PROTO_OFFSET;
- ip_len = IP_LEN;
- sol = SOL_IP;
- ipsec_policy = IP_IPSEC_POLICY;
- break;
- case AF_INET6:
- proto_offset = IP6_PROTO_OFFSET;
- ip_len = 0; /* IPv6 raw sockets contain no IP header */
- sol = SOL_IPV6;
- ipsec_policy = IPV6_IPSEC_POLICY;
- break;
- default:
- return 0;
- }
- udp_header = ip_len;
- ike_header = ip_len + UDP_LEN;
-
- /* This filter code filters out all non-IKEv2 traffic on
- * a SOCK_RAW IP_PROTP_UDP socket. Handling of other
- * IKE versions is done in pluto.
- */
- struct sock_filter ikev2_filter_code[] =
- {
- /* 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, this->port, 1, 0),
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->natt_port, 5, 12),
- /* port */
- /* IKE version must be 2.0 */
- BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + IKE_VERSION_OFFSET),
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10),
- /* 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),
- BPF_STMT(BPF_RET+BPF_A, 0),
- /* 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_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),
- /* 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),
- BPF_STMT(BPF_RET+BPF_A, 0),
- /* packet doesn't match, ignore */
- BPF_STMT(BPF_RET+BPF_K, 0),
- };
-
- /* Filter struct to use with setsockopt */
- struct sock_fprog ikev2_filter = {
- sizeof(ikev2_filter_code) / sizeof(struct sock_filter),
- ikev2_filter_code
- };
-
- /* set up a raw socket */
- skt = socket(family, SOCK_RAW, IPPROTO_UDP);
- if (skt < 0)
- {
- DBG1(DBG_NET, "unable to create raw socket: %s", strerror(errno));
- return 0;
- }
-
- if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER,
- &ikev2_filter, sizeof(ikev2_filter)) < 0)
- {
- DBG1(DBG_NET, "unable to attach IKEv2 filter to raw socket: %s",
- strerror(errno));
+ DBG1(DBG_NET, "unable to set IP_PKTINFO on socket: %s", strerror(errno));
close(skt);
return 0;
}
- if (family == AF_INET6 &&
- /* we use IPV6_2292PKTINFO, as IPV6_PKTINFO is defined as
- * 2 or 50 depending on kernel header version */
- setsockopt(skt, sol, IPV6_2292PKTINFO, &on, sizeof(on)) < 0)
+ /* enable UDP decapsulation globally, only for one socket needed */
+ if (family == AF_INET && port == IKEV2_NATT_PORT &&
+ setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
{
- DBG1(DBG_NET, "unable to set IPV6_PKTINFO on raw socket: %s",
- strerror(errno));
- close(skt);
- return 0;
- }
-
- /* bypass incomining IKE traffic on this socket */
- memset(&policy, 0, sizeof(policy));
- policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
- policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
- policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
- policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
-
- if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
- {
- DBG1(DBG_NET, "unable to set IPSEC_POLICY on raw socket: %s",
- strerror(errno));
- close(skt);
- return 0;
+ DBG1(DBG_NET, "unable to set UDP_ENCAP: %s", strerror(errno));
}
-
return skt;
}
@@ -658,29 +507,21 @@ static int open_recv_socket(private_socket_t *this, int family)
*/
static void destroy(private_socket_t *this)
{
- if (this->recv4)
- {
- close(this->recv4);
- }
- if (this->recv6)
- {
- close(this->recv6);
- }
- if (this->send4)
+ if (this->ipv4)
{
- close(this->send4);
+ close(this->ipv4);
}
- if (this->send6)
+ if (this->ipv4_natt)
{
- close(this->send6);
+ close(this->ipv4_natt);
}
- if (this->send4_natt)
+ if (this->ipv6)
{
- close(this->send4_natt);
+ close(this->ipv6);
}
- if (this->send6_natt)
+ if (this->ipv6_natt)
{
- close(this->send6_natt);
+ close(this->ipv6_natt);
}
free(this);
}
@@ -688,7 +529,7 @@ static void destroy(private_socket_t *this)
/*
* See header for description
*/
-socket_t *socket_create(u_int16_t port, u_int16_t natt_port)
+socket_t *socket_create()
{
int key;
private_socket_t *this = malloc_thing(private_socket_t);
@@ -698,14 +539,10 @@ socket_t *socket_create(u_int16_t port, u_int16_t natt_port)
this->public.receive = (status_t(*)(socket_t*, packet_t**))receiver;
this->public.destroy = (void(*)(socket_t*)) destroy;
- this->port = port;
- this->natt_port = natt_port;
- this->recv4 = 0;
- this->recv6 = 0;
- this->send4 = 0;
- this->send6 = 0;
- this->send4_natt = 0;
- this->send6_natt = 0;
+ this->ipv4 = 0;
+ this->ipv6 = 0;
+ this->ipv4_natt = 0;
+ this->ipv6_natt = 0;
/* we open a AF_KEY socket to autoload the af_key module. Otherwise
* setsockopt(IPSEC_POLICY) won't work. */
@@ -715,59 +552,41 @@ socket_t *socket_create(u_int16_t port, u_int16_t natt_port)
charon->kill(charon, "could not open AF_KEY socket");
}
close(key);
-
- this->recv4 = open_recv_socket(this, AF_INET);
- if (this->recv4 == 0)
+
+ this->ipv4 = open_socket(this, AF_INET, IKEV2_UDP_PORT);
+ if (this->ipv4 == 0)
{
- DBG1(DBG_NET, "could not open IPv4 receive socket, IPv4 disabled");
+ DBG1(DBG_NET, "could not open IPv4 socket, IPv4 disabled");
}
else
{
- this->send4 = open_send_socket(this, AF_INET, this->port);
- if (this->send4 == 0)
+ this->ipv4_natt = open_socket(this, AF_INET, IKEV2_NATT_PORT);
+ if (this->ipv4_natt == 0)
{
- DBG1(DBG_NET, "could not open IPv4 send socket, IPv4 disabled");
- close(this->recv4);
- }
- else
- {
- this->send4_natt = open_send_socket(this, AF_INET, this->natt_port);
- if (this->send4_natt == 0)
- {
- DBG1(DBG_NET, "could not open IPv4 NAT-T send socket");
- }
+ DBG1(DBG_NET, "could not open IPv4 NAT-T socket");
}
}
-
- this->recv6 = open_recv_socket(this, AF_INET6);
- if (this->recv6 == 0)
+
+ this->ipv6 = open_socket(this, AF_INET6, IKEV2_UDP_PORT);
+ if (this->ipv6 == 0)
{
- DBG1(DBG_NET, "could not open IPv6 receive socket, IPv6 disabled");
+ DBG1(DBG_NET, "could not open IPv6 socket, IPv6 disabled");
}
else
{
- this->send6 = open_send_socket(this, AF_INET6, this->port);
- if (this->send6 == 0)
+ this->ipv6_natt = open_socket(this, AF_INET6, IKEV2_NATT_PORT);
+ if (this->ipv6_natt == 0)
{
- DBG1(DBG_NET, "could not open IPv6 send socket, IPv6 disabled");
- close(this->recv6);
- }
- else
- {
- this->send6_natt = open_send_socket(this, AF_INET6, this->natt_port);
- if (this->send6_natt == 0)
- {
- DBG1(DBG_NET, "could not open IPv6 NAT-T send socket");
- }
+ DBG1(DBG_NET, "could not open IPv6 NAT-T socket");
}
}
- if (!(this->send4 || this->send6) || !(this->recv4 || this->recv6))
+ if (!this->ipv4 && !this->ipv6)
{
DBG1(DBG_NET, "could not create any sockets");
destroy(this);
charon->kill(charon, "socket initialization failed");
- }
-
+ }
return (socket_t*)this;
}
+
diff --git a/src/charon/network/socket.h b/src/charon/network/socket.h
index ef60fa7b6..4d8251325 100644
--- a/src/charon/network/socket.h
+++ b/src/charon/network/socket.h
@@ -100,13 +100,11 @@ struct socket_t {
/**
* @brief Create a socket_t, wich binds multiple sockets.
*
- * @param port port to bind socket to
- * @param natt_port port to float to in NAT-T
* @return socket_t object
*
* @ingroup network
*/
-socket_t *socket_create(u_int16_t port, u_int16_t natt_port);
+socket_t *socket_create();
#endif /*SOCKET_H_*/
diff --git a/src/charon/processing/jobs/callback_job.c b/src/charon/processing/jobs/callback_job.c
index 6f534e0f7..53297916e 100644
--- a/src/charon/processing/jobs/callback_job.c
+++ b/src/charon/processing/jobs/callback_job.c
@@ -121,12 +121,7 @@ static void cancel(private_callback_job_t *this)
{
pthread_t thread;
- /* wait until thread has started */
pthread_mutex_lock(&this->mutex);
- while (this->thread == 0)
- {
- pthread_cond_wait(&this->condvar, &this->mutex);
- }
thread = this->thread;
/* terminate its children */
@@ -134,8 +129,11 @@ static void cancel(private_callback_job_t *this)
pthread_mutex_unlock(&this->mutex);
/* terminate thread */
- pthread_cancel(thread);
- pthread_join(thread, NULL);
+ if (thread)
+ {
+ pthread_cancel(thread);
+ pthread_join(thread, NULL);
+ }
}
/**
@@ -159,6 +157,7 @@ static void execute(private_callback_job_t *this)
continue;
case JOB_REQUEUE_FAIR:
{
+ this->thread = 0;
charon->processor->queue_job(charon->processor,
&this->public.job_interface);
break;
@@ -166,6 +165,7 @@ static void execute(private_callback_job_t *this)
case JOB_REQUEUE_NONE:
default:
{
+ this->thread = 0;
cleanup = TRUE;
break;
}
diff --git a/src/charon/processing/jobs/initiate_mediation_job.c b/src/charon/processing/jobs/initiate_mediation_job.c
index d78f8a202..b8d516e22 100644
--- a/src/charon/processing/jobs/initiate_mediation_job.c
+++ b/src/charon/processing/jobs/initiate_mediation_job.c
@@ -73,7 +73,7 @@ static bool initiate_callback(private_initiate_mediation_job_t *this, signal_t s
{
if (signal == CHILD_UP_SUCCESS)
{
- // mediation connection is up
+ /* mediation connection is up */
this->mediation_sa_id = ike_sa->get_id(ike_sa);
this->mediation_sa_id = this->mediation_sa_id->clone(this->mediation_sa_id);
return FALSE;
@@ -85,7 +85,7 @@ static bool initiate_callback(private_initiate_mediation_job_t *this, signal_t s
* Implementation of job_t.execute.
*/
static void initiate(private_initiate_mediation_job_t *this)
-{//FIXME: check the logging
+{ /* FIXME: check the logging */
ike_sa_t *mediated_sa, *mediation_sa;
peer_cfg_t *mediated_cfg, *mediation_cfg;
@@ -94,7 +94,8 @@ static void initiate(private_initiate_mediation_job_t *this)
if (mediated_sa)
{
mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
- mediated_cfg->get_ref(mediated_cfg); // get_peer_cfg returns an internal object
+ /* get_peer_cfg returns an internal object */
+ mediated_cfg->get_ref(mediated_cfg);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
@@ -107,18 +108,19 @@ static void initiate(private_initiate_mediation_job_t *this)
{
mediated_cfg->destroy(mediated_cfg);
mediation_cfg->destroy(mediation_cfg);
- charon->bus->set_sa(charon->bus, mediated_sa); // this pointer should still be valid
+ /* this pointer should still be valid */
+ charon->bus->set_sa(charon->bus, mediated_sa);
DBG1(DBG_IKE, "mediation with the same peer is already in progress, queued");
destroy(this);
return;
}
-
- mediation_cfg->get_ref(mediation_cfg); // we need an additional reference because initiate consumes one
+ /* we need an additional reference because initiate consumes one */
+ mediation_cfg->get_ref(mediation_cfg);
- // this function call blocks until the connection is up or failed
- // we do not check the status, but NEED_MORE would be returned on success
- // because the registered callback returns FALSE then
- // this->mediation_sa_id is set in the callback
+ /* this function call blocks until the connection is up or failed
+ * we do not check the status, but NEED_MORE would be returned on success
+ * because the registered callback returns FALSE then
+ * this->mediation_sa_id is set in the callback */
charon->interfaces->initiate(charon->interfaces,
mediation_cfg, NULL, (interface_manager_cb_t)initiate_callback, this);
if (!this->mediation_sa_id)
@@ -127,7 +129,7 @@ static void initiate(private_initiate_mediation_job_t *this)
mediation_cfg->get_name(mediation_cfg));
mediation_cfg->destroy(mediation_cfg);
mediated_cfg->destroy(mediated_cfg);
- charon->bus->set_sa(charon->bus, mediated_sa); // this pointer should still be valid
+ charon->bus->set_sa(charon->bus, mediated_sa);
SIG(IKE_UP_FAILED, "mediation failed");
destroy(this);
return;
@@ -146,7 +148,7 @@ static void initiate(private_initiate_mediation_job_t *this)
mediated_cfg->destroy(mediated_cfg);
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
- charon->bus->set_sa(charon->bus, mediated_sa); // this pointer should still be valid
+ charon->bus->set_sa(charon->bus, mediated_sa);
SIG(IKE_UP_FAILED, "mediation failed");
destroy(this);
return;
@@ -164,7 +166,7 @@ static void initiate(private_initiate_mediation_job_t *this)
* Implementation of job_t.execute.
*/
static void reinitiate(private_initiate_mediation_job_t *this)
-{//FIXME: check the logging
+{ /* FIXME: check the logging */
ike_sa_t *mediated_sa, *mediation_sa;
peer_cfg_t *mediated_cfg;
@@ -173,7 +175,7 @@ static void reinitiate(private_initiate_mediation_job_t *this)
if (mediated_sa)
{
mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
- mediated_cfg->get_ref(mediated_cfg); // get_peer_cfg returns an internal object
+ mediated_cfg->get_ref(mediated_cfg);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
@@ -187,7 +189,7 @@ static void reinitiate(private_initiate_mediation_job_t *this)
mediated_cfg->destroy(mediated_cfg);
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
- charon->bus->set_sa(charon->bus, mediated_sa); // this pointer should still be valid
+ charon->bus->set_sa(charon->bus, mediated_sa);
SIG(IKE_UP_FAILED, "mediation failed");
destroy(this);
return;
diff --git a/src/charon/processing/jobs/mediation_job.c b/src/charon/processing/jobs/mediation_job.c
index 6f5f74372..3b9d363d7 100644
--- a/src/charon/processing/jobs/mediation_job.c
+++ b/src/charon/processing/jobs/mediation_job.c
@@ -104,7 +104,7 @@ static void execute(private_mediation_job_t *this)
{
if (this->callback)
{
- // send callback to a peer
+ /* send callback to a peer */
if (target_sa->callback(target_sa, this->source) != SUCCESS)
{
DBG1(DBG_JOB, "callback for '%D' to '%D' failed",
@@ -116,14 +116,14 @@ static void execute(private_mediation_job_t *this)
}
else
{
- // normal mediation between two peers
+ /* normal mediation between two peers */
if (target_sa->relay(target_sa, this->source, this->session_id,
this->session_key, this->endpoints, this->response) != SUCCESS)
{
DBG1(DBG_JOB, "mediation between '%D' and '%D' failed",
this->source, this->target);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa);
- // FIXME: notify the initiator
+ /* FIXME: notify the initiator */
destroy(this);
return;
}
diff --git a/src/charon/processing/jobs/process_message_job.c b/src/charon/processing/jobs/process_message_job.c
index ec2e7735d..91e7a80bf 100644
--- a/src/charon/processing/jobs/process_message_job.c
+++ b/src/charon/processing/jobs/process_message_job.c
@@ -60,12 +60,13 @@ static void execute(private_process_message_job_t *this)
ike_sa_t *ike_sa;
#ifdef P2P
- // if this is an unencrypted INFORMATIONAL exchange it is likely a
- // connectivity check
+ /* if this is an unencrypted INFORMATIONAL exchange it is likely a
+ * connectivity check. */
if (this->message->get_exchange_type(this->message) == INFORMATIONAL &&
this->message->get_first_payload_type(this->message) != ENCRYPTED)
{
- // theoretically this could also be an error message see RFC 4306, section 1.5.
+ /* theoretically this could also be an error message
+ * see RFC 4306, section 1.5. */
DBG1(DBG_NET, "received unencrypted informational: from %#H to %#H",
this->message->get_source(this->message),
this->message->get_destination(this->message));
diff --git a/src/charon/processing/scheduler.c b/src/charon/processing/scheduler.c
index 2706585b0..ededb479a 100644
--- a/src/charon/processing/scheduler.c
+++ b/src/charon/processing/scheduler.c
@@ -87,6 +87,8 @@ struct private_scheduler_t {
* Condvar to wait for next job.
*/
pthread_cond_t condvar;
+
+ bool cancelled;
};
/**
@@ -148,9 +150,7 @@ static job_requeue_t schedule(private_scheduler_t * this)
pthread_cond_wait(&this->condvar, &this->mutex);
}
pthread_setcancelstate(oldstate, NULL);
- pthread_cleanup_pop(0);
-
- pthread_mutex_unlock(&this->mutex);
+ pthread_cleanup_pop(TRUE);
return JOB_REQUEUE_DIRECT;
}
@@ -234,6 +234,7 @@ static void schedule_job(private_scheduler_t *this, job_t *job, u_int32_t time)
*/
static void destroy(private_scheduler_t *this)
{
+ this->cancelled = TRUE;
this->job->cancel(this->job);
this->list->destroy_function(this->list, (void*)event_destroy);
free(this);
@@ -251,6 +252,7 @@ scheduler_t * scheduler_create()
this->public.destroy = (void(*)(scheduler_t*)) destroy;
this->list = linked_list_create();
+ this->cancelled = FALSE;
pthread_mutex_init(&this->mutex, NULL);
pthread_cond_init(&this->condvar, NULL);
diff --git a/src/charon/sa/authenticators/eap/eap_aka.c b/src/charon/sa/authenticators/eap/eap_aka.c
new file mode 100644
index 000000000..8fb1f85cd
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_aka.c
@@ -0,0 +1,1440 @@
+/**
+ * @file eap_aka.c
+ *
+ * @brief Implementation of eap_aka_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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.
+ */
+
+
+/* The EAP-AKA method uses it's own simple parser for processing EAP-AKA
+ * payloads, as the IKEv2 parser is not suitable for that job. There are
+ * two simple methods for parsing payloads, read_header() and read_attribute().
+ * Every EAP-AKA payload consists of a header and a list of attributes. Those
+ * functions mentioned read the data and return the type of the found
+ * attribute/EAP-AKA-type. For generating a EAP-AKA message, we have a
+ * build_aka_payload(), which builds the whole message from a variable
+ * argument list containing its attributes.
+ * The processing of messages is split up in various functions:
+ * - peer_process() - General processing multiplexer for the peer
+ * - peer_process_challenge() - Specific AKA-Challenge processor
+ * - peer_process_notification() - Processing of AKA-Notification
+ * - server_process() - General processing multiplexer for the server
+ * - peer_process_challenge() - Processing of a received Challenge response
+ * - peer_process_synchronize() - Process a sequence number synchronization
+ * - server_initiate() - Initiation method for the server, calls
+ * - server_initiate_challenge() - Initiation of AKA-Challenge
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "eap_aka.h"
+
+#include <daemon.h>
+#include <library.h>
+#include <utils/randomizer.h>
+#include <crypto/hashers/hasher.h>
+#include <crypto/prfs/fips_prf.h>
+
+/* Use test vectors specified in S.S0055
+#define TEST_VECTORS */
+
+#define RAND_LENGTH 16
+#define RES_LENGTH 16
+#define SQN_LENGTH 6
+#define K_LENGTH 16
+#define MAC_LENGTH 8
+#define CK_LENGTH 16
+#define IK_LENGTH 16
+#define AK_LENGTH 6
+#define AMF_LENGTH 2
+#define FMK_LENGTH 4
+#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH)
+#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH)
+#define PAYLOAD_LENGTH 64
+#define MK_LENGTH 20
+#define MSK_LENGTH 64
+#define EMSK_LENGTH 64
+#define KAUTH_LENGTH 16
+#define KENCR_LENGTH 16
+#define AT_MAC_LENGTH 16
+
+#define F1 0x42
+#define F1STAR 0x43
+#define F2 0x44
+#define F3 0x45
+#define F4 0x46
+#define F5 0x47
+#define F5STAR 0x48
+
+ENUM_BEGIN(aka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY,
+ "AKA_CHALLENGE",
+ "AKA_AUTHENTICATION_REJECT",
+ "AKA_3",
+ "AKA_SYNCHRONIZATION_FAILURE",
+ "AKA_IDENTITY");
+ENUM_NEXT(aka_subtype_names, AKA_NOTIFICATION, AKA_CLIENT_ERROR, AKA_IDENTITY,
+ "AKA_NOTIFICATION",
+ "AKA_REAUTHENTICATION",
+ "AKA_CLIENT_ERROR");
+ENUM_END(aka_subtype_names, AKA_CLIENT_ERROR);
+
+
+ENUM_BEGIN(aka_attribute_names, AT_END, AT_CLIENT_ERROR_CODE,
+ "AT_END",
+ "AT_0",
+ "AT_RAND",
+ "AT_AUTN",
+ "AT_RES",
+ "AT_AUTS",
+ "AT_5",
+ "AT_PADDING",
+ "AT_NONCE_MT",
+ "AT_8",
+ "AT_9",
+ "AT_PERMANENT_ID_REQ",
+ "AT_MAC",
+ "AT_NOTIFICATION",
+ "AT_ANY_ID_REQ",
+ "AT_IDENTITY",
+ "AT_VERSION_LIST",
+ "AT_SELECTED_VERSION",
+ "AT_FULLAUTH_ID_REQ",
+ "AT_18",
+ "AT_COUNTER",
+ "AT_COUNTER_TOO_SMALL",
+ "AT_NONCE_S",
+ "AT_CLIENT_ERROR_CODE");
+ENUM_NEXT(aka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
+ "AT_IV",
+ "AT_ENCR_DATA",
+ "AT_131",
+ "AT_NEXT_PSEUDONYM",
+ "AT_NEXT_REAUTH_ID",
+ "AT_CHECKCODE",
+ "AT_RESULT_IND");
+ENUM_END(aka_attribute_names, AT_RESULT_IND);
+
+
+typedef struct private_eap_aka_t private_eap_aka_t;
+
+/**
+ * Private data of an eap_aka_t object.
+ */
+struct private_eap_aka_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ eap_aka_t public;
+
+ /**
+ * ID of the server
+ */
+ identification_t *server;
+
+ /**
+ * ID of the peer
+ */
+ identification_t *peer;
+
+ /**
+ * Key for EAP MAC
+ */
+ chunk_t k_auth;
+
+ /**
+ * Key for EAP encryption
+ */
+ chunk_t k_encr;
+
+ /**
+ * MSK
+ */
+ chunk_t msk;
+
+ /**
+ * Extendend MSK
+ */
+ chunk_t emsk;
+
+ /**
+ * Expected result from client XRES
+ */
+ chunk_t xres;
+
+ /**
+ * Shared secret K from ipsec.conf (padded)
+ */
+ chunk_t k;
+
+ /**
+ * random value RAND generated by server
+ */
+ chunk_t rand;
+};
+
+/** Family key, as proposed in S.S0055 */
+static u_int8_t fmk_buf[] = {0x41, 0x48, 0x41, 0x47};
+static chunk_t fmk = chunk_from_buf(fmk_buf);
+
+/** Authentication management field */
+static u_int8_t amf_buf[] = {0x00, 0x01};
+static chunk_t amf = chunk_from_buf(amf_buf);
+
+/** AT_CLIENT_ERROR_CODE AKA attribute */
+static u_int8_t client_error_code_buf[] = {0, 0};
+static chunk_t client_error_code = chunk_from_buf(client_error_code_buf);
+
+/** previously used sqn by peer, next one must be greater */
+static u_int8_t peer_sqn_buf[6];
+static chunk_t peer_sqn = chunk_from_buf(peer_sqn_buf);
+
+/** set SQN to the current time */
+static void update_sqn(u_int8_t *sqn, time_t offset)
+{
+ timeval_t time;
+ gettimeofday(&time, NULL);
+ /* set sqb_sqn to an integer containing seconds followed by most
+ * significant useconds */
+ time.tv_sec = htonl(time.tv_sec + offset);
+ /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */
+ time.tv_usec <<= 12;
+ time.tv_usec = htonl(time.tv_usec);
+ memcpy(sqn, &time.tv_sec, 4);
+ memcpy(sqn + 4, &time.tv_usec, 2);
+}
+
+/** initialize peers SQN to the current system time at startup */
+static void __attribute__ ((constructor))init_sqn(void)
+{
+ update_sqn(peer_sqn_buf, 0);
+}
+
+/**
+ * Binary represnation of the polynom T^160 + T^5 + T^3 + T^2 + 1
+ */
+static u_int8_t g[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2d
+};
+
+/**
+ * Predefined random bits from the RAND Corporation book
+ */
+static u_int8_t a[] = {
+ 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11,
+ 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49,
+ 0x3f, 0x4c, 0x63, 0x65
+};
+
+/**
+ * Predefined random bits from the RAND Corporation book
+ */
+static u_int8_t b[] = {
+ 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51,
+ 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e,
+ 0x7e, 0xec, 0x45, 0xe0
+};
+
+/**
+ * Multiplicate two mpz_t with bits interpreted as polynoms.
+ */
+static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b)
+{
+ mpz_t bm, rm;
+ int current = 0, shifted = 0, shift;
+
+ mpz_init_set(bm, b);
+ mpz_init_set_ui(rm, 0);
+ /* scan through a, for each found bit: */
+ while ((current = mpz_scan1(a, current)) != ULONG_MAX)
+ {
+ /* XOR shifted b into r */
+ shift = current - shifted;
+ mpz_mul_2exp(bm, bm, shift);
+ shifted += shift;
+ mpz_xor(rm, rm, bm);
+ current++;
+ }
+
+ mpz_swap(r, rm);
+ mpz_clear(rm);
+ mpz_clear(bm);
+}
+
+/**
+ * Calculate the sum of a + b interpreted as polynoms.
+ */
+static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b)
+{
+ /* addition of polynominals is just the XOR */
+ mpz_xor(res, a, b);
+}
+
+/**
+ * Calculate the remainder of a/b interpreted as polynoms.
+ */
+static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b)
+{
+ /* Example:
+ * a = 10001010
+ * b = 00000101
+ */
+ int a_bit, b_bit, diff;
+ mpz_t bm, am;
+
+ mpz_init_set(am, a);
+ mpz_init(bm);
+
+ a_bit = mpz_sizeinbase(a, 2);
+ b_bit = mpz_sizeinbase(b, 2);
+
+ /* don't do anything if b > a */
+ if (a_bit >= b_bit)
+ {
+ /* shift b left to align up most signaficant "1" to a:
+ * a = 10001010
+ * b = 10100000
+ */
+ mpz_mul_2exp(bm, b, a_bit - b_bit);
+ do
+ {
+ /* XOR b into a, this kills the most significant "1":
+ * a = 00101010
+ */
+ mpz_xor(am, am, bm);
+ /* find the next most significant "1" in a, and align up b:
+ * a = 00101010
+ * b = 00101000
+ */
+ diff = a_bit - mpz_sizeinbase(am, 2);
+ mpz_div_2exp(bm, bm, diff);
+ a_bit -= diff;
+ }
+ while (b_bit <= mpz_sizeinbase(bm, 2));
+ /* While b is not shifted to its original value */
+ }
+ /* after another iteration:
+ * a = 00000010
+ * which is the polynomial modulo
+ */
+
+ mpz_swap(r, am);
+ mpz_clear(am);
+ mpz_clear(bm);
+}
+
+/**
+ * Step 4 of the various fx() functions:
+ * Polynomial whiten calculations
+ */
+static void step4(u_int8_t x[])
+{
+ mpz_t xm, am, bm, gm;
+
+ mpz_init(xm);
+ mpz_init(am);
+ mpz_init(bm);
+ mpz_init(gm);
+
+ mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x);
+ mpz_import(am, sizeof(a), 1, 1, 1, 0, a);
+ mpz_import(bm, sizeof(b), 1, 1, 1, 0, b);
+ mpz_import(gm, sizeof(g), 1, 1, 1, 0, g);
+
+ mpz_mul_poly(xm, am, xm);
+ mpz_add_poly(xm, bm, xm);
+ mpz_mod_poly(xm, xm, gm);
+
+ mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm);
+
+ mpz_clear(xm);
+ mpz_clear(am);
+ mpz_clear(bm);
+ mpz_clear(gm);
+}
+
+/**
+ * Step 3 of the various fx() functions:
+ * XOR the key into the SHA1 IV
+ */
+static void step3(chunk_t k, chunk_t payload, u_int8_t h[])
+{
+ u_int8_t iv[] = {
+ 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA,
+ 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0,
+ };
+
+ /* XOR key into IV */
+ memxor(iv, k.ptr, k.len);
+
+ /* hash it with the G() function defined in FIPS 186-2 from fips_prf.h */
+ g_sha1(iv, payload, h);
+}
+
+/**
+ * Calculation function for f2(), f3(), f4()
+ */
+static void fx(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t out[])
+{
+ chunk_t payload = chunk_alloca(PAYLOAD_LENGTH);
+ u_int8_t h[HASH_SIZE_SHA1];
+ u_int8_t i;
+
+ for (i = 0; i < 2; i++)
+ {
+ memset(payload.ptr, 0x5c, payload.len);
+ payload.ptr[11] ^= f;
+ memxor(payload.ptr + 12, fmk.ptr, fmk.len);
+ memxor(payload.ptr + 24, rand.ptr, rand.len);
+
+ payload.ptr[3] ^= i;
+ payload.ptr[19] ^= i;
+ payload.ptr[35] ^= i;
+ payload.ptr[51] ^= i;
+
+ step3(k, payload, h);
+ step4(h);
+ memcpy(out + i * 8, h, 8);
+ }
+}
+
+/**
+ * Calculation function of f1() and f1star()
+ */
+static void f1x(u_int8_t f, chunk_t k, chunk_t rand, chunk_t sqn,
+ chunk_t amf, u_int8_t mac[])
+{
+ /* generate MAC = f1(FMK, SQN, RAND, AMF)
+ * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit
+ * payload which gets hashed
+ */
+ chunk_t payload = chunk_alloca(PAYLOAD_LENGTH);
+ u_int8_t h[HASH_SIZE_SHA1];
+
+ memset(payload.ptr, 0x5c, PAYLOAD_LENGTH);
+ payload.ptr[11] ^= f;
+ memxor(payload.ptr + 12, fmk.ptr, fmk.len);
+ memxor(payload.ptr + 16, rand.ptr, rand.len);
+ memxor(payload.ptr + 34, sqn.ptr, sqn.len);
+ memxor(payload.ptr + 42, amf.ptr, amf.len);
+
+ step3(k, payload, h);
+ step4(h);
+ memcpy(mac, h, MAC_LENGTH);
+}
+
+/**
+ * Calculation function of f5() and f5star()
+ */
+static void f5x(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t ak[])
+{
+ chunk_t payload = chunk_alloca(PAYLOAD_LENGTH);
+ u_int8_t h[HASH_SIZE_SHA1];
+
+ memset(payload.ptr, 0x5c, payload.len);
+ payload.ptr[11] ^= f;
+ memxor(payload.ptr + 12, fmk.ptr, fmk.len);
+ memxor(payload.ptr + 16, rand.ptr, rand.len);
+
+ step3(k, payload, h);
+ step4(h);
+ memcpy(ak, h, AK_LENGTH);
+}
+
+/**
+ * Calculate the MAC from a RAND, SQN, AMF value using K
+ */
+static void f1(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t mac[])
+{
+ f1x(F1, k, rand, sqn, amf, mac);
+ DBG3(DBG_IKE, "MAC %b", mac, MAC_LENGTH);
+}
+
+/**
+ * Calculate the MACS from a RAND, SQN, AMF value using K
+ */
+static void f1star(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t macs[])
+{
+ f1x(F1STAR, k, rand, sqn, amf, macs);
+ DBG3(DBG_IKE, "MACS %b", macs, MAC_LENGTH);
+}
+
+/**
+ * Calculate RES from RAND using K
+ */
+static void f2(chunk_t k, chunk_t rand, u_int8_t res[])
+{
+ fx(F2, k, rand, res);
+ DBG3(DBG_IKE, "RES %b", res, RES_LENGTH);
+}
+
+/**
+ * Calculate CK from RAND using K
+ */
+static void f3(chunk_t k, chunk_t rand, u_int8_t ck[])
+{
+ fx(F3, k, rand, ck);
+ DBG3(DBG_IKE, "CK %b", ck, CK_LENGTH);
+}
+
+/**
+ * Calculate IK from RAND using K
+ */
+static void f4(chunk_t k, chunk_t rand, u_int8_t ik[])
+{
+ fx(F4, k, rand, ik);
+ DBG3(DBG_IKE, "IK %b", ik, IK_LENGTH);
+}
+
+/**
+ * Calculate AK from a RAND using K
+ */
+static void f5(chunk_t k, chunk_t rand, u_int8_t ak[])
+{
+ f5x(F5, k, rand, ak);
+ DBG3(DBG_IKE, "AK %b", ak, AK_LENGTH);
+}
+
+/**
+ * Calculate AKS from a RAND using K
+ */
+static void f5star(chunk_t k, chunk_t rand, u_int8_t aks[])
+{
+ f5x(F5STAR, k, rand, aks);
+ DBG3(DBG_IKE, "AKS %b", aks, AK_LENGTH);
+}
+
+/**
+ * derive the keys needed for EAP_AKA
+ */
+static void derive_keys(private_eap_aka_t *this, identification_t *id)
+{
+ hasher_t *hasher;
+ prf_t *prf;
+ chunk_t ck, ik, mk, identity, tmp;
+
+ ck = chunk_alloca(CK_LENGTH);
+ ik = chunk_alloca(IK_LENGTH);
+ mk = chunk_alloca(MK_LENGTH);
+ identity = id->get_encoding(id);
+
+ /* MK = SHA1( Identity | IK | CK ) */
+ f3(this->k, this->rand, ck.ptr);
+ f4(this->k, this->rand, ik.ptr);
+ DBG3(DBG_IKE, "Identity %B", &identity);
+ tmp = chunk_cata("ccc", identity, ik, ck);
+ DBG3(DBG_IKE, "Identity|IK|CK %B", &tmp);
+ hasher = hasher_create(HASH_SHA1);
+ hasher->get_hash(hasher, tmp, mk.ptr);
+ hasher->destroy(hasher);
+
+ /* K_encr | K_auth | MSK | EMSK = prf(0) | prf(0)
+ * FIPS PRF has 320 bit block size, we need 160 byte for keys
+ * => run prf four times */
+ prf = prf_create(PRF_FIPS_SHA1_160);
+ prf->set_key(prf, mk);
+ tmp = chunk_alloca(prf->get_block_size(prf) * 4);
+ prf->get_bytes(prf, chunk_empty, tmp.ptr);
+ prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 1);
+ prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 2);
+ prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 3);
+ prf->destroy(prf);
+ chunk_free(&this->k_encr);
+ chunk_free(&this->k_auth);
+ chunk_free(&this->msk);
+ chunk_free(&this->emsk);
+ chunk_split(tmp, "aaaa", 16, &this->k_encr, 16, &this->k_auth,
+ 64, &this->msk, 64, &this->emsk);
+ DBG3(DBG_IKE, "MK %B", &mk);
+ DBG3(DBG_IKE, "PRF res %B", &tmp);
+ DBG3(DBG_IKE, "K_encr %B", &this->k_encr);
+ DBG3(DBG_IKE, "K_auth %B", &this->k_auth);
+ DBG3(DBG_IKE, "MSK %B", &this->msk);
+ DBG3(DBG_IKE, "EMSK %B", &this->emsk);
+}
+
+/*
+ * Get a shared key from ipsec.secrets.
+ * We use the standard keys as used in preshared key authentication. As
+ * these keys have an undefined length, we:
+ * - strip them if they are longer
+ * - fill them up with '\0' if they are shorter
+ */
+static status_t load_key(identification_t *me, identification_t *other, chunk_t *k)
+{
+ chunk_t shared_key;
+
+ if (charon->credentials->get_eap_key(charon->credentials, me,
+ other, &shared_key) != SUCCESS)
+ {
+ return NOT_FOUND;
+ }
+ chunk_free(k);
+ *k = chunk_alloc(K_LENGTH);
+ memset(k->ptr, '\0', k->len);
+ memcpy(k->ptr, shared_key.ptr, min(shared_key.len, k->len));
+ chunk_free(&shared_key);
+ return SUCCESS;
+}
+
+/**
+ * skip EAP_AKA header in message and returns its AKA subtype
+ */
+static aka_subtype_t read_header(chunk_t *message)
+{
+ aka_subtype_t type;
+
+ if (message->len < 8)
+ {
+ *message = chunk_empty;
+ return 0;
+ }
+ type = *(message->ptr + 5);
+ *message = chunk_skip(*message, 8);
+ return type;
+}
+
+/**
+ * read the next attribute from the chunk data
+ */
+static aka_attribute_t read_attribute(chunk_t *data, chunk_t *attr_data)
+{
+ aka_attribute_t attribute;
+ size_t length;
+
+ DBG3(DBG_IKE, "reading attribute from %B", data);
+
+ if (data->len < 2)
+ {
+ return AT_END;
+ }
+ /* read attribute and length */
+ attribute = *data->ptr++;
+ length = *data->ptr++ * 4 - 2;
+ data->len -= 2;
+ DBG3(DBG_IKE, "found attribute %N with length %d",
+ aka_attribute_names, attribute, length);
+ if (length > data->len)
+ {
+ return AT_END;
+ }
+ /* apply attribute value to attr_data */
+ attr_data->len = length;
+ attr_data->ptr = data->ptr;
+ /* update data to point to next attribute */
+ *data = chunk_skip(*data, length);
+ return attribute;
+}
+
+/**
+ * Build an AKA payload from different attributes.
+ * The variable argument takes an aka_attribute_t
+ * followed by its data in a chunk.
+ */
+static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code,
+ u_int8_t identifier, aka_subtype_t type, ...)
+{
+ chunk_t message = chunk_alloca(512); /* is enought for all current messages */
+ chunk_t pos = message;
+ eap_payload_t *payload;
+ va_list args;
+ aka_attribute_t attr;
+ u_int8_t *mac_pos = NULL;
+
+ /* write EAP header, skip length bytes */
+ *pos.ptr++ = code;
+ *pos.ptr++ = identifier;
+ pos.ptr += 2;
+ pos.len -= 4;
+ /* write AKA header with type and subtype, null reserved bytes */
+ *pos.ptr++ = EAP_AKA;
+ *pos.ptr++ = type;
+ *pos.ptr++ = 0;
+ *pos.ptr++ = 0;
+ pos.len -= 4;
+
+ va_start(args, type);
+ while ((attr = va_arg(args, aka_attribute_t)) != AT_END)
+ {
+ chunk_t data = va_arg(args, chunk_t);
+
+ DBG3(DBG_IKE, "building %N %B", aka_attribute_names, attr, &data);
+
+ /* write attribute header */
+ *pos.ptr++ = attr;
+ pos.len--;
+
+ switch (attr)
+ {
+ case AT_RES:
+ {
+ /* attribute length in 4byte words */
+ *pos.ptr = data.len/4 + 1;
+ pos = chunk_skip(pos, 1);
+ /* RES length in bits */
+ *(u_int16_t*)pos.ptr = htons(data.len * 8);
+ pos = chunk_skip(pos, sizeof(u_int16_t));
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ break;
+ }
+ case AT_AUTN:
+ case AT_RAND:
+ {
+ *pos.ptr++ = data.len/4 + 1; pos.len--;
+ *pos.ptr++ = 0; pos.len--;
+ *pos.ptr++ = 0; pos.len--;
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ break;
+ }
+ case AT_MAC:
+ {
+ *pos.ptr++ = 5; pos.len--;
+ *pos.ptr++ = 0; pos.len--;
+ *pos.ptr++ = 0; pos.len--;
+ mac_pos = pos.ptr;
+ /* MAC is calculated over message including zeroed AT_MAC attribute */
+ memset(mac_pos, 0, AT_MAC_LENGTH);
+ pos.ptr += AT_MAC_LENGTH;
+ pos.len -= AT_MAC_LENGTH;
+ break;
+ }
+ default:
+ {
+ /* length is data length in 4-bytes + 1 for header */
+ *pos.ptr = data.len/4 + 1;
+ pos = chunk_skip(pos, 1);
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ }
+ }
+ }
+ va_end(args);
+
+ /* calculate message length, write into header */
+ message.len = pos.ptr - message.ptr;
+ *(u_int16_t*)(message.ptr + 2) = htons(message.len);
+
+ /* create MAC if AT_MAC attribte was included */
+ if (mac_pos)
+ {
+ signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
+ signer->set_key(signer, this->k_auth);
+ DBG3(DBG_IKE, "AT_MAC signature of %B", &message);
+ DBG3(DBG_IKE, "using key %B", &this->k_auth);
+ signer->get_signature(signer, message, mac_pos);
+ DBG3(DBG_IKE, "is %b", mac_pos, AT_MAC_LENGTH);
+ signer->destroy(signer);
+ }
+
+ /* payload constructor takes data with some bytes skipped */
+ payload = eap_payload_create_data(message);
+
+ DBG3(DBG_IKE, "created EAP message %B", &message);
+ return payload;
+}
+
+/**
+ * Initiate a AKA-Challenge using SQN
+ */
+static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, eap_payload_t **out)
+{
+ randomizer_t *randomizer;
+ status_t status;
+ chunk_t mac, ak, autn;
+
+ mac = chunk_alloca(MAC_LENGTH);
+ ak = chunk_alloca(AK_LENGTH);
+ chunk_free(&this->rand);
+ chunk_free(&this->xres);
+
+ /* generate RAND:
+ * we use our standard randomizer, not f0() proposed in S.S0055
+ */
+ randomizer = randomizer_create();
+ status = randomizer->allocate_pseudo_random_bytes(randomizer, RAND_LENGTH, &this->rand);
+ randomizer->destroy(randomizer);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "generating RAND for EAP-AKA authentication failed");
+ return FAILED;
+ }
+
+# ifdef TEST_VECTORS
+ /* Test vector for RAND */
+ u_int8_t test_rand[] = {
+ 0x4b,0x05,0x2b,0x20,0xe2,0xa0,0x6c,0x8f,
+ 0xf7,0x00,0xda,0x51,0x2b,0x4e,0x11,0x1e,
+ };
+ memcpy(this->rand.ptr, test_rand, this->rand.len);
+# endif /* TEST_VECTORS */
+
+ /* Get the shared key K: */
+ if (load_key(this->server, this->peer, &this->k) != SUCCESS)
+ {
+ DBG1(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate "
+ "with EAP-AKA", this->server, this->peer);
+ return FAILED;
+ }
+
+# ifdef TEST_VECTORS
+ /* Test vector for K */
+ u_int8_t test_k[] = {
+ 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c,
+ 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d,
+ };
+ memcpy(this->k.ptr, test_k, this->k.len);
+# endif /* TEST_VECTORS */
+
+ /* generate MAC */
+ f1(this->k, this->rand, sqn, amf, mac.ptr);
+
+ /* generate AK */
+ f5(this->k, this->rand, ak.ptr);
+
+ /* precalculate XRES as expected from client */
+ this->xres = chunk_alloc(RES_LENGTH);
+ f2(this->k, this->rand, this->xres.ptr);
+
+ /* calculate AUTN = (SQN xor AK) || AMF || MAC */
+ autn = chunk_cata("ccc", sqn, amf, mac);
+ memxor(autn.ptr, ak.ptr, ak.len);
+ DBG3(DBG_IKE, "AUTN %B", &autn);
+
+
+ /* derive K_encr, K_auth, MSK, EMSK */
+ derive_keys(this, this->peer);
+
+ /* build payload */
+ *out = build_aka_payload(this, EAP_REQUEST, 0, AKA_CHALLENGE,
+ AT_RAND, this->rand, AT_AUTN, autn, AT_MAC,
+ chunk_empty, AT_END);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of eap_method_t.initiate for an EAP_AKA server
+ */
+static status_t server_initiate(private_eap_aka_t *this, eap_payload_t **out)
+{
+ chunk_t sqn = chunk_alloca(SQN_LENGTH);
+
+ /* we use an offset of 3 minutes to tolerate clock inaccuracy
+ * without the need to synchronize sequence numbers */
+ update_sqn(sqn.ptr, 180);
+
+# ifdef TEST_VECTORS
+ /* Test vector for SQN */
+ u_int8_t test_sqn[] = {0x00,0x00,0x00,0x00,0x00,0x01};
+ memcpy(sqn.ptr, test_sqn, sqn.len);
+# endif /* TEST_VECTORS */
+
+ return server_initiate_challenge(this, sqn, out);
+}
+
+static status_t server_process_synchronize(private_eap_aka_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t attr, auts = chunk_empty, pos, message, macs, xmacs, sqn, aks, amf;
+ u_int i;
+
+ message = in->get_data(in);
+ pos = message;
+ read_header(&pos);
+
+ /* iterate over attributes */
+ while (TRUE)
+ {
+ aka_attribute_t attribute = read_attribute(&pos, &attr);
+ switch (attribute)
+ {
+ case AT_END:
+ break;
+ case AT_AUTS:
+ auts = attr;
+ continue;
+ default:
+ if (attribute >= 0 && attribute <= 127)
+ {
+ DBG1(DBG_IKE, "found non skippable attribute %N",
+ aka_attribute_names, attribute);
+ return FAILED;
+ }
+ DBG1(DBG_IKE, "ignoring skippable attribute %N",
+ aka_attribute_names, attribute);
+ continue;
+ }
+ break;
+ }
+
+ if (auts.len != AUTS_LENGTH)
+ {
+ DBG1(DBG_IKE, "synchronization request didn't contain useable AUTS");
+ return FAILED;
+ }
+
+ chunk_split(auts, "mm", SQN_LENGTH, &sqn, MAC_LENGTH, &macs);
+ aks = chunk_alloca(AK_LENGTH);
+ f5star(this->k, this->rand, aks.ptr);
+ /* decrypt serial number by XORing AKS */
+ memxor(sqn.ptr, aks.ptr, aks.len);
+
+ /* verify MACS */
+ xmacs = chunk_alloca(MAC_LENGTH);
+ amf = chunk_alloca(AMF_LENGTH);
+ /* an AMF of zero is used for MACS calculation */
+ memset(amf.ptr, 0, amf.len);
+ f1star(this->k, this->rand, sqn, amf, xmacs.ptr);
+ if (!chunk_equals(macs, xmacs))
+ {
+ DBG1(DBG_IKE, "received MACS does not match XMACS");
+ DBG3(DBG_IKE, "MACS %B XMACS %B", &macs, &xmacs);
+ return FAILED;
+ }
+
+ /* retry the challenge with the received SQN + 1*/
+ for (i = SQN_LENGTH - 1; i >= 0; i--)
+ {
+ if (++sqn.ptr[i] != 0)
+ {
+ break;
+ }
+ }
+ return server_initiate_challenge(this, sqn, out);
+}
+
+/**
+ * process an AKA_Challenge response
+ */
+static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t *in)
+{
+ chunk_t attr, res = chunk_empty, at_mac = chunk_empty, pos, message;
+
+ message = in->get_data(in);
+ pos = message;
+ read_header(&pos);
+
+ /* iterate over attributes */
+ while (TRUE)
+ {
+ aka_attribute_t attribute = read_attribute(&pos, &attr);
+ switch (attribute)
+ {
+ case AT_END:
+ break;
+ case AT_RES:
+ res = attr;
+ if (attr.len == 2 + RES_LENGTH &&
+ *(u_int16_t*)attr.ptr == htons(RES_LENGTH * 8))
+ {
+ res = chunk_skip(attr, 2);
+ }
+ continue;
+
+ case AT_MAC:
+ attr = chunk_skip(attr, 2);
+ at_mac = chunk_clonea(attr);
+ /* zero MAC in message for MAC verification */
+ memset(attr.ptr, 0, attr.len);
+ continue;
+ default:
+ if (attribute >= 0 && attribute <= 127)
+ {
+ DBG1(DBG_IKE, "found non skippable attribute %N",
+ aka_attribute_names, attribute);
+ return FAILED;
+ }
+ DBG1(DBG_IKE, "ignoring skippable attribute %N",
+ aka_attribute_names, attribute);
+ continue;
+ }
+ break;
+ }
+
+ /* verify EAP message MAC AT_MAC */
+ {
+ bool valid;
+ signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
+ signer->set_key(signer, this->k_auth);
+ DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message);
+ DBG3(DBG_IKE, "using key %B", &this->k_auth);
+ valid = signer->verify_signature(signer, message, at_mac);
+ signer->destroy(signer);
+ if (!valid)
+ {
+ DBG1(DBG_IKE, "MAC in AT_MAC attribute verification failed");
+ return FAILED;
+ }
+ }
+
+ /* compare received RES against stored precalculated XRES */
+ if (!chunk_equals(res, this->xres))
+ {
+ DBG1(DBG_IKE, "received RES does not match XRES");
+ DBG3(DBG_IKE, "RES %Bb XRES %B", &res, &this->xres);
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of eap_method_t.process for EAP_AKA servers
+ */
+static status_t server_process(private_eap_aka_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t message;
+ aka_subtype_t type;
+
+ message = in->get_data(in);
+ type = read_header(&message);
+
+ DBG3(DBG_IKE, "received EAP message %B", &message);
+
+ switch (type)
+ {
+ case AKA_CHALLENGE:
+ {
+ return server_process_challenge(this, in);
+ }
+ case AKA_AUTHENTICATION_REJECT:
+ case AKA_CLIENT_ERROR:
+ {
+ DBG1(DBG_IKE, "received %N, authentication failed",
+ aka_subtype_names, type);
+ return FAILED;
+ }
+ case AKA_SYNCHRONIZATION_FAILURE:
+ {
+ DBG1(DBG_IKE, "received %N, retrying with received SQN",
+ aka_subtype_names, type);
+ return server_process_synchronize(this, in, out);
+ }
+ default:
+ DBG1(DBG_IKE, "received unknown AKA subtype %N, authentication failed",
+ aka_subtype_names, type);
+ return FAILED;
+ }
+}
+
+/**
+ * Process an incoming AKA-Challenge client side
+ */
+static status_t peer_process_challenge(private_eap_aka_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t attr = chunk_empty;
+ chunk_t autn = chunk_empty, at_mac = chunk_empty;
+ chunk_t ak, sqn, sqn_ak, mac, xmac, res, amf, message, pos;
+ u_int8_t identifier;
+
+ ak = chunk_alloca(AK_LENGTH);
+ xmac = chunk_alloca(MAC_LENGTH);
+ res = chunk_alloca(RES_LENGTH);
+ chunk_free(&this->rand);
+
+ message = in->get_data(in);
+ pos = message;
+ read_header(&pos);
+ identifier = in->get_identifier(in);
+
+ DBG3(DBG_IKE, "reading attributes from %B", &pos);
+
+ /* iterate over attributes */
+ while (TRUE)
+ {
+ aka_attribute_t attribute = read_attribute(&pos, &attr);
+ switch (attribute)
+ {
+ case AT_END:
+ break;
+ case AT_RAND:
+ this->rand = chunk_clone(chunk_skip(attr, 2));
+ continue;
+ case AT_AUTN:
+ autn = chunk_skip(attr, 2);
+ continue;
+ case AT_MAC:
+ attr = chunk_skip(attr, 2);
+ at_mac = chunk_clonea(attr);
+ /* set MAC in message to zero for own MAC verification */
+ memset(attr.ptr, 0, attr.len);
+ continue;
+ default:
+ if (attribute >= 0 && attribute <= 127)
+ {
+ /* non skippable attribute, abort */
+ *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_code, AT_END);
+ DBG1(DBG_IKE, "found non skippable attribute %N, sending %N %d",
+ aka_attribute_names, attribute,
+ aka_attribute_names, AT_CLIENT_ERROR_CODE, 0);
+ return NEED_MORE;
+ }
+ DBG1(DBG_IKE, "ignoring skippable attribute %N",
+ aka_attribute_names, attribute);
+ continue;
+ }
+ break;
+ }
+
+ if (this->rand.len != RAND_LENGTH || autn.len != AUTN_LENGTH)
+ {
+ /* required attributes wrong/not found, abort */
+ *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_code, AT_END);
+ DBG1(DBG_IKE, "could not find valid RAND/AUTN attribute, sending %N %d",
+ aka_attribute_names, AT_CLIENT_ERROR_CODE, 0);
+ return NEED_MORE;
+ }
+
+ DBG3(DBG_IKE, "using autn %B", &autn);
+ /* split up AUTN = SQN xor AK | AMF | MAC */
+ chunk_split(autn, "mmm", SQN_LENGTH, &sqn_ak, AMF_LENGTH, &amf, MAC_LENGTH, &mac);
+
+ /* Get the shared key K: */
+ chunk_free(&this->k);
+ if (load_key(this->peer, this->server, &this->k) != SUCCESS)
+ {
+ *out = build_aka_payload(this, EAP_RESPONSE, identifier,
+ AKA_AUTHENTICATION_REJECT, AT_END);
+ DBG3(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate "
+ "with EAP-AKA, sending %N", this->peer, this->server,
+ aka_subtype_names, AKA_AUTHENTICATION_REJECT);
+ return NEED_MORE;
+ }
+ DBG3(DBG_IKE, "using K %B", &this->k);
+# ifdef TEST_VECTORS
+ /* Test vector for K */
+ u_int8_t test_k[] = {
+ 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c,
+ 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d,
+ };
+ memcpy(this->k.ptr, test_k, this->k.len);
+# endif /* TEST_VECTORS */
+
+ /* calculate anonymity key AK */
+ f5(this->k, this->rand, ak.ptr);
+ DBG3(DBG_IKE, "using rand %B", &this->rand);
+ DBG3(DBG_IKE, "using ak %B", &ak);
+ /* XOR AK into SQN to decrypt it */
+
+ sqn = chunk_clonea(sqn_ak);
+
+ DBG3(DBG_IKE, "using ak xor sqn %B", &sqn_ak);
+ memxor(sqn.ptr, ak.ptr, sqn.len);
+ DBG3(DBG_IKE, "using sqn %B", &sqn);
+
+ /* calculate expected MAC and compare against received one */
+ f1(this->k, this->rand, sqn, amf, xmac.ptr);
+ if (!chunk_equals(mac, xmac))
+ {
+ *out = build_aka_payload(this, EAP_RESPONSE, identifier,
+ AKA_AUTHENTICATION_REJECT, AT_END);
+ DBG1(DBG_IKE, "received MAC does not match XMAC, sending %N",
+ aka_subtype_names, AKA_AUTHENTICATION_REJECT);
+ DBG3(DBG_IKE, "MAC %B\nXMAC %B", &mac, &xmac);
+ return NEED_MORE;
+ }
+
+#if SEQ_CHECK
+ if (memcmp(peer_sqn.ptr, sqn.ptr, sqn.len) >= 0)
+ {
+ /* sequence number invalid. send AUTS */
+ chunk_t auts, macs, aks, amf;
+
+ macs = chunk_alloca(MAC_LENGTH);
+ aks = chunk_alloca(AK_LENGTH);
+ amf = chunk_alloca(AMF_LENGTH);
+
+ /* AMF is set to zero in AKA_SYNCHRONIZATION_FAILURE */
+ memset(amf.ptr, 0, amf.len);
+ /* AKS = f5*(RAND) */
+ f5star(this->k, this->rand, aks.ptr);
+ /* MACS = f1*(RAND) */
+ f1star(this->k, this->rand, peer_sqn, amf, macs.ptr);
+ /* AUTS = SQN xor AKS | MACS */
+ memxor(aks.ptr, peer_sqn.ptr, aks.len);
+ auts = chunk_cata("cc", aks, macs);
+
+ *out = build_aka_payload(this, EAP_RESPONSE, identifier,
+ AKA_SYNCHRONIZATION_FAILURE,
+ AT_AUTS, auts, AT_END);
+ DBG1(DBG_IKE, "received SQN invalid, sending %N",
+ aka_subtype_names, AKA_SYNCHRONIZATION_FAILURE);
+ DBG3(DBG_IKE, "received SQN %B\ncurrent SQN %B", &sqn, &peer_sqn);
+ return NEED_MORE;
+ }
+#endif /* SEQ_CHECK */
+
+ /* derive K_encr, K_auth, MSK, EMSK */
+ derive_keys(this, this->peer);
+
+ /* verify EAP message MAC AT_MAC */
+ {
+ bool valid;
+ signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
+ signer->set_key(signer, this->k_auth);
+
+ DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message);
+ DBG3(DBG_IKE, "using key %B", &this->k_auth);
+ valid = signer->verify_signature(signer, message, at_mac);
+ signer->destroy(signer);
+ if (!valid)
+ {
+ *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_code, AT_END);
+ DBG1(DBG_IKE, "MAC in AT_MAC attribute verification "
+ "failed, sending %N %d", aka_attribute_names,
+ AT_CLIENT_ERROR_CODE, 0);
+ return NEED_MORE;
+ }
+ }
+
+ /* update stored SQN to the received one */
+ memcpy(peer_sqn.ptr, sqn.ptr, sqn.len);
+
+ /* calculate RES */
+ f2(this->k, this->rand, res.ptr);
+
+ /* build response */
+ *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CHALLENGE,
+ AT_RES, res, AT_MAC, chunk_empty, AT_END);
+ return NEED_MORE;
+}
+
+/**
+ * Process an incoming AKA-Notification as client
+ */
+static status_t peer_process_notification(private_eap_aka_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t message, pos, attr;
+ u_int8_t identifier;
+
+ message = in->get_data(in);
+ pos = message;
+ read_header(&pos);
+ identifier = in->get_identifier(in);
+
+ DBG3(DBG_IKE, "reading attributes from %B", &pos);
+
+ /* iterate over attributes */
+ while (TRUE)
+ {
+ aka_attribute_t attribute = read_attribute(&pos, &attr);
+ switch (attribute)
+ {
+ case AT_END:
+ break;
+ case AT_NOTIFICATION:
+ {
+ u_int16_t code;
+
+ if (attr.len != 2)
+ {
+ DBG1(DBG_IKE, "received invalid AKA notification, ignored");
+ continue;
+ }
+ code = ntohs(*(u_int16_t*)attr.ptr);
+ switch (code)
+ {
+ case 0:
+ DBG1(DBG_IKE, "received AKA notification 'general "
+ "failure after authentication' (%d)", code);
+ return FAILED;
+ case 16384:
+ DBG1(DBG_IKE, "received AKA notification 'general "
+ "failure' (%d)", code);
+ return FAILED;
+ case 32768:
+ DBG1(DBG_IKE, "received AKA notification 'successfully "
+ "authenticated' (%d)", code);
+ continue;
+ case 1026:
+ DBG1(DBG_IKE, "received AKA notification 'access "
+ "temporarily denied' (%d)", code);
+ return FAILED;
+ case 1031:
+ DBG1(DBG_IKE, "received AKA notification 'not "
+ "subscribed to service' (%d)", code);
+ return FAILED;
+ default:
+ DBG1(DBG_IKE, "received AKA notification code %d, "
+ "ignored", code);
+ continue;
+ }
+ }
+ default:
+ if (attribute >= 0 && attribute <= 127)
+ {
+ DBG1(DBG_IKE, "ignoring non-skippable attribute %N in %N",
+ aka_attribute_names, attribute, aka_subtype_names,
+ AKA_NOTIFICATION);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "ignoring skippable attribute %N",
+ aka_attribute_names, attribute);
+ }
+ continue;
+ }
+ break;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of eap_method_t.process for an EAP_AKA peer
+ */
+static status_t peer_process(private_eap_aka_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ aka_subtype_t type;
+ chunk_t message;
+ u_int8_t identifier;
+
+ message = in->get_data(in);
+ type = read_header(&message);
+ identifier = in->get_identifier(in);
+
+ DBG3(DBG_IKE, "received EAP message %B", &message);
+
+ switch (type)
+ {
+ case AKA_CHALLENGE:
+ {
+ return peer_process_challenge(this, in, out);
+ }
+ case AKA_NOTIFICATION:
+ {
+ return peer_process_notification(this, in, out);
+ }
+ default:
+ {
+ *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_code, AT_END);
+ DBG1(DBG_IKE, "received unsupported %N request, sending %N %d",
+ aka_subtype_names, type,
+ aka_attribute_names, AT_CLIENT_ERROR_CODE, 0);
+ return NEED_MORE;
+ }
+ }
+}
+
+/**
+ * Implementation of eap_method_t.initiate for an EAP AKA peer
+ */
+static status_t peer_initiate(private_eap_aka_t *this, eap_payload_t **out)
+{
+ /* peer never initiates */
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.get_type.
+ */
+static eap_type_t get_type(private_eap_aka_t *this, u_int32_t *vendor)
+{
+ *vendor = 0;
+ return EAP_AKA;
+}
+
+/**
+ * Implementation of eap_method_t.get_msk.
+ */
+static status_t get_msk(private_eap_aka_t *this, chunk_t *msk)
+{
+ if (this->msk.ptr)
+ {
+ *msk = this->msk;
+ return SUCCESS;
+ }
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.is_mutual.
+ */
+static bool is_mutual(private_eap_aka_t *this)
+{
+ return TRUE;
+}
+
+/**
+ * Implementation of eap_method_t.destroy.
+ */
+static void destroy(private_eap_aka_t *this)
+{
+ chunk_free(&this->k_encr);
+ chunk_free(&this->k_auth);
+ chunk_free(&this->msk);
+ chunk_free(&this->emsk);
+ chunk_free(&this->xres);
+ chunk_free(&this->k);
+ chunk_free(&this->rand);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+eap_aka_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer)
+{
+ private_eap_aka_t *this = malloc_thing(private_eap_aka_t);
+
+ /* public functions */
+ switch (role)
+ {
+ case EAP_SERVER:
+ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate;
+ this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process;
+ break;
+ case EAP_PEER:
+ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate;
+ this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process;
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+ 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 data */
+ this->server = server;
+ this->peer = peer;
+ this->k_encr = chunk_empty;
+ this->k_auth = chunk_empty;
+ this->msk = chunk_empty;
+ this->emsk = chunk_empty;
+ this->xres = chunk_empty;
+ this->k = chunk_empty;
+ this->rand = chunk_empty;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/eap/eap_aka.h b/src/charon/sa/authenticators/eap/eap_aka.h
new file mode 100644
index 000000000..a886863be
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_aka.h
@@ -0,0 +1,141 @@
+/**
+ * @file eap_aka.h
+ *
+ * @brief Interface of eap_aka_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef EAP_AKA_H_
+#define EAP_AKA_H_
+
+typedef struct eap_aka_t eap_aka_t;
+typedef enum aka_subtype_t aka_subtype_t;
+typedef enum aka_attribute_t aka_attribute_t;
+
+#include <sa/authenticators/eap/eap_method.h>
+
+
+/**
+ * Subtypes of AKA messages
+ */
+enum aka_subtype_t {
+ AKA_CHALLENGE = 1,
+ AKA_AUTHENTICATION_REJECT = 2,
+ AKA_SYNCHRONIZATION_FAILURE = 4,
+ AKA_IDENTITY = 5,
+ AKA_NOTIFICATION = 12,
+ AKA_REAUTHENTICATION = 13,
+ AKA_CLIENT_ERROR = 14,
+};
+
+/**
+ * enum names for aka_subtype_t
+ */
+extern enum_name_t *aka_subtype_names;
+
+/**
+ * Attribute types in AKA messages
+ */
+enum aka_attribute_t {
+ /** defines the end of attribute list */
+ AT_END = -1,
+ AT_RAND = 1,
+ AT_AUTN = 2,
+ AT_RES = 3,
+ AT_AUTS = 4,
+ AT_PADDING = 6,
+ AT_NONCE_MT = 7,
+ AT_PERMANENT_ID_REQ = 10,
+ AT_MAC = 11,
+ AT_NOTIFICATION = 12,
+ AT_ANY_ID_REQ = 13,
+ AT_IDENTITY = 14,
+ AT_VERSION_LIST = 15,
+ AT_SELECTED_VERSION = 16,
+ AT_FULLAUTH_ID_REQ = 17,
+ AT_COUNTER = 19,
+ AT_COUNTER_TOO_SMALL = 20,
+ AT_NONCE_S = 21,
+ AT_CLIENT_ERROR_CODE = 22,
+ AT_IV = 129,
+ AT_ENCR_DATA = 130,
+ AT_NEXT_PSEUDONYM = 132,
+ AT_NEXT_REAUTH_ID = 133,
+ AT_CHECKCODE = 134,
+ AT_RESULT_IND = 135,
+};
+
+/**
+ * enum names for aka_attribute_t
+ */
+extern enum_name_t *aka_attribute_names;
+
+/** check SEQ values as client for validity, disabled by default */
+#ifndef SEQ_CHECK
+# define SEQ_CHECK 0
+#endif
+
+/**
+ * @brief Implementation of the eap_method_t interface using EAP-AKA.
+ *
+ * EAP-AKA uses 3rd generation mobile phone standard authentication
+ * mechanism for authentication. It is a mutual authentication
+ * mechanism which establishs a shared key and therefore supports EAP_ONLY
+ * authentication. This implementation follows the standard of the
+ * 3GPP2 (S.S0055) and not the one of 3GGP.
+ * The shared key used for authentication is from ipsec.secrets. The
+ * peers ID is used to query it.
+ * The AKA mechanism uses sequence numbers to detect replay attacks. The
+ * peer stores the sequence number normally in a USIM and accepts
+ * incremental sequence numbers (incremental for lifetime of the USIM). To
+ * prevent a complex sequence number management, this implementation uses
+ * a sequence number derived from time. It is initialized to the startup
+ * time of the daemon. As long as the (UTC) time of the system is not
+ * turned back while the daemon is not running, this method is secure.
+ * To enable time based SEQs, #define SEQ_CHECK as 1. Default is to accept
+ * any SEQ numbers. This allows an attacker to do replay attacks. But since
+ * the server has proven his identity via IKE, such an attack is only
+ * possible between server and AAA (if any).
+ *
+ * @b Constructors:
+ * - eap_aka_create()
+ * - eap_client_create() using eap_method EAP_AKA
+ *
+ * @ingroup eap
+ */
+struct eap_aka_t {
+
+ /**
+ * Implemented eap_method_t interface.
+ */
+ eap_method_t eap_method_interface;
+};
+
+/**
+ * @brief Creates the EAP method EAP-AKA.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return eap_aka_t object
+ *
+ * @ingroup eap
+ */
+eap_aka_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer);
+
+#endif /* EAP_AKA_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_md5.c b/src/charon/sa/authenticators/eap/eap_md5.c
new file mode 100644
index 000000000..0ca9fc566
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_md5.c
@@ -0,0 +1,282 @@
+/**
+ * @file eap_md5.c
+ *
+ * @brief Implementation of eap_md5_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 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 "eap_md5.h"
+
+#include <daemon.h>
+#include <library.h>
+
+typedef struct private_eap_md5_t private_eap_md5_t;
+
+/**
+ * Private data of an eap_md5_t object.
+ */
+struct private_eap_md5_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ eap_md5_t public;
+
+ /**
+ * ID of the server
+ */
+ identification_t *server;
+
+ /**
+ * ID of the peer
+ */
+ identification_t *peer;
+
+ /**
+ * challenge sent by the server
+ */
+ chunk_t challenge;
+
+ /**
+ * EAP message identififier
+ */
+ u_int8_t identifier;
+};
+
+typedef struct eap_md5_header_t eap_md5_header_t;
+
+/**
+ * packed eap MD5 header struct
+ */
+struct eap_md5_header_t {
+ /** EAP code (REQUEST/RESPONSE) */
+ u_int8_t code;
+ /** unique message identifier */
+ u_int8_t identifier;
+ /** length of whole message */
+ u_int16_t length;
+ /** EAP type */
+ u_int8_t type;
+ /** length of value (challenge) */
+ u_int8_t value_size;
+ /** actual value */
+ u_int8_t value[];
+} __attribute__((__packed__));
+
+#define CHALLENGE_LEN 16
+#define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t))
+
+/**
+ * Hash the challenge string, create response
+ */
+static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response)
+{
+ chunk_t concat, secret;
+ hasher_t *hasher;
+
+ if (charon->credentials->get_eap_key(charon->credentials, this->server,
+ this->peer, &secret) != SUCCESS)
+ {
+ DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'",
+ this->server, this->peer);
+ return NOT_FOUND;
+ }
+ concat = chunk_cata("cmc", chunk_from_thing(this->identifier),
+ secret, this->challenge);
+ hasher = hasher_create(HASH_MD5);
+ hasher->allocate_hash(hasher, concat, response);
+ hasher->destroy(hasher);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of eap_method_t.initiate for the peer
+ */
+static status_t initiate_peer(private_eap_md5_t *this, eap_payload_t **out)
+{
+ /* peer never initiates */
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.initiate for the server
+ */
+static status_t initiate_server(private_eap_md5_t *this, eap_payload_t **out)
+{
+ randomizer_t *randomizer;
+ status_t status;
+ eap_md5_header_t *req;
+
+ randomizer = randomizer_create();
+ status = randomizer->allocate_pseudo_random_bytes(randomizer, CHALLENGE_LEN,
+ &this->challenge);
+ randomizer->destroy(randomizer);
+ if (status != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ req = alloca(PAYLOAD_LEN);
+ req->length = htons(PAYLOAD_LEN);
+ req->code = EAP_REQUEST;
+ req->identifier = this->identifier;
+ req->type = EAP_MD5;
+ req->value_size = this->challenge.len;
+ memcpy(req->value, this->challenge.ptr, this->challenge.len);
+
+ *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN));
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of eap_method_t.process for the peer
+ */
+static status_t process_peer(private_eap_md5_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t response;
+ chunk_t data;
+ eap_md5_header_t *req;
+
+ this->identifier = in->get_identifier(in);
+ data = in->get_data(in);
+ this->challenge = chunk_clone(chunk_skip(data, 6));
+ if (data.len < 6 || this->challenge.len < *(data.ptr + 5))
+ {
+ DBG1(DBG_IKE, "received invalid EAP-MD5 message");
+ return FAILED;
+ }
+ if (hash_challenge(this, &response) != SUCCESS)
+ {
+ return FAILED;
+ }
+ req = alloca(PAYLOAD_LEN);
+ req->length = htons(PAYLOAD_LEN);
+ req->code = EAP_RESPONSE;
+ req->identifier = this->identifier;
+ req->type = EAP_MD5;
+ req->value_size = response.len;
+ memcpy(req->value, response.ptr, response.len);
+ chunk_free(&response);
+
+ *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN));
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of eap_method_t.process for the server
+ */
+static status_t process_server(private_eap_md5_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t response, expected;
+ chunk_t data;
+
+ if (this->identifier != in->get_identifier(in))
+ {
+ DBG1(DBG_IKE, "received invalid EAP-MD5 message");
+ return FAILED;
+ }
+ if (hash_challenge(this, &expected) != SUCCESS)
+ {
+ return FAILED;
+ }
+ data = in->get_data(in);
+ response = chunk_skip(data, 6);
+
+ if (response.len < expected.len ||
+ !memeq(response.ptr, expected.ptr, expected.len))
+ {
+ chunk_free(&expected);
+ DBG1(DBG_IKE, "EAP-MD5 verification failed");
+ return FAILED;
+ }
+ chunk_free(&expected);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of eap_method_t.get_type.
+ */
+static eap_type_t get_type(private_eap_md5_t *this, u_int32_t *vendor)
+{
+ *vendor = 0;
+ return EAP_MD5;
+}
+
+/**
+ * Implementation of eap_method_t.get_msk.
+ */
+static status_t get_msk(private_eap_md5_t *this, chunk_t *msk)
+{
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.is_mutual.
+ */
+static bool is_mutual(private_eap_md5_t *this)
+{
+ return FALSE;
+}
+
+/**
+ * Implementation of eap_method_t.destroy.
+ */
+static void destroy(private_eap_md5_t *this)
+{
+ chunk_free(&this->challenge);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+eap_md5_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer)
+{
+ private_eap_md5_t *this = malloc_thing(private_eap_md5_t);
+
+ /* public functions */
+ switch (role)
+ {
+ case EAP_SERVER:
+ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server;
+ this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_server;
+ break;
+ case EAP_PEER:
+ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer;
+ this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_peer;
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+ 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 data */
+ this->peer = peer;
+ this->server = server;
+ this->challenge = chunk_empty;
+ this->identifier = random();
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/eap/eap_md5.h b/src/charon/sa/authenticators/eap/eap_md5.h
new file mode 100644
index 000000000..260210b59
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_md5.h
@@ -0,0 +1,59 @@
+/**
+ * @file eap_md5.h
+ *
+ * @brief Interface of eap_md5_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef EAP_MD5_H_
+#define EAP_MD5_H_
+
+typedef struct eap_md5_t eap_md5_t;
+
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * @brief Implementation of the eap_method_t interface using EAP-MD5 (CHAP).
+ *
+ * @b Constructors:
+ * - eap_md5_create()
+ * - eap_client_create() using eap_method EAP_MD5
+ *
+ * @ingroup eap
+ */
+struct eap_md5_t {
+
+ /**
+ * Implemented eap_method_t interface.
+ */
+ eap_method_t eap_method_interface;
+};
+
+/**
+ * @brief Creates the EAP method EAP-MD5.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return eap_md5_t object
+ *
+ * @ingroup eap
+ */
+eap_md5_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer);
+
+#endif /* EAP_MD5_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c
index e4a58f0a3..7434ca2a1 100644
--- a/src/charon/sa/authenticators/eap/eap_method.c
+++ b/src/charon/sa/authenticators/eap/eap_method.c
@@ -45,7 +45,10 @@ ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_TOKEN_CARD,
"EAP_SIM");
ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM,
"EAP_AKA");
-ENUM_END(eap_type_names, EAP_AKA);
+ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_EXPERIMENTAL, EAP_AKA,
+ "EAP_EXPANDED",
+ "EAP_EXPERIMENTAL");
+ENUM_END(eap_type_names, EAP_EXPERIMENTAL);
ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE,
"EAP_REQUEST",
@@ -67,6 +70,7 @@ typedef struct module_entry_t module_entry_t;
*/
struct module_entry_t {
eap_type_t type;
+ u_int32_t vendor;
void *handle;
eap_constructor_t constructor;
};
@@ -85,7 +89,8 @@ void eap_method_unload()
while (modules->remove_last(modules, (void**)&entry) == SUCCESS)
{
- DBG2(DBG_CFG, "unloaded module for %N", eap_type_names, entry->type);
+ DBG2(DBG_CFG, "unloaded module EAP module %d-%d",
+ entry->type, entry->vendor);
dlclose(entry->handle);
free(entry);
}
@@ -165,11 +170,19 @@ void eap_method_load(char *directory)
dlclose(module.handle);
continue;
}
- module.type = method->get_type(method);
+ module.type = method->get_type(method, &module.vendor);
method->destroy(method);
- DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
- eap_type_names, module.type, entry->d_name);
+ if (module.vendor)
+ {
+ DBG1(DBG_CFG, " loaded EAP method %d, vendor %d successfully from %s",
+ module.type, module.vendor, entry->d_name);
+ }
+ else
+ {
+ DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
+ eap_type_names, module.type, entry->d_name);
+ }
loaded_module = malloc_thing(module_entry_t);
memcpy(loaded_module, &module, sizeof(module));
@@ -181,9 +194,8 @@ void eap_method_load(char *directory)
/*
* Described in header.
*/
-eap_method_t *eap_method_create(eap_type_t type, eap_role_t role,
- identification_t *server,
- identification_t *peer)
+eap_method_t *eap_method_create(eap_type_t type, u_int32_t vendor, eap_role_t role,
+ identification_t *server, identification_t *peer)
{
eap_method_t *method = NULL;
iterator_t *iterator;
@@ -192,7 +204,7 @@ eap_method_t *eap_method_create(eap_type_t type, eap_role_t role,
iterator = modules->create_iterator(modules, TRUE);
while (iterator->iterate(iterator, (void**)&entry))
{
- if (entry->type == type)
+ if (entry->type == type && entry->vendor == vendor)
{
method = entry->constructor(role, server, peer);
if (method)
@@ -205,8 +217,16 @@ eap_method_t *eap_method_create(eap_type_t type, eap_role_t role,
if (method == NULL)
{
- DBG1(DBG_CFG, "no EAP module found for %N %N",
- eap_type_names, type, eap_role_names, role);
+ if (vendor)
+ {
+ DBG1(DBG_CFG, "no vendor %d specific EAP module found for method "
+ "%d %N", vendor, type, eap_role_names, role);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "no EAP module found for %N %N",
+ eap_type_names, type, eap_role_names, role);
+ }
}
return method;
}
diff --git a/src/charon/sa/authenticators/eap/eap_method.h b/src/charon/sa/authenticators/eap/eap_method.h
index d43dc001f..8675fd8ec 100644
--- a/src/charon/sa/authenticators/eap/eap_method.h
+++ b/src/charon/sa/authenticators/eap/eap_method.h
@@ -62,6 +62,8 @@ enum eap_type_t {
EAP_TOKEN_CARD = 6,
EAP_SIM = 18,
EAP_AKA = 23,
+ EAP_EXPANDED = 254,
+ EAP_EXPERIMENTAL = 255,
};
/**
@@ -148,9 +150,10 @@ struct eap_method_t {
* @brief Get the EAP type implemented in this method.
*
* @param this calling object
+ * @param vendor pointer receiving vendor identifier for type, 0 for none
* @return type of the EAP method
*/
- eap_type_t (*get_type) (eap_method_t *this);
+ eap_type_t (*get_type) (eap_method_t *this, u_int32_t *vendor);
/**
* @brief Check if this EAP method authenticates the server.
@@ -188,6 +191,7 @@ struct eap_method_t {
* @brief Creates an EAP method for a specific type and role.
*
* @param eap_type EAP type to use
+ * @param eap_vendor vendor identifier if a vendor specifc EAP type is used
* @param role role of the eap_method, server or peer
* @param server ID of acting server
* @param peer ID of involved peer (client)
@@ -195,8 +199,9 @@ struct eap_method_t {
*
* @ingroup eap
*/
-eap_method_t *eap_method_create(eap_type_t eap_type, eap_role_t role,
- identification_t *server, identification_t *peer);
+eap_method_t *eap_method_create(eap_type_t eap_type, u_int32_t eap_vendor,
+ eap_role_t role, identification_t *server,
+ identification_t *peer);
/**
* @brief (Re-)Load all EAP modules in the EAP modules directory.
diff --git a/src/charon/sa/authenticators/eap/eap_sim.c b/src/charon/sa/authenticators/eap/eap_sim.c
index 38d7f2534..c9eb5ce8f 100644
--- a/src/charon/sa/authenticators/eap/eap_sim.c
+++ b/src/charon/sa/authenticators/eap/eap_sim.c
@@ -264,6 +264,7 @@ static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier
}
case AT_IDENTITY:
{
+ u_int16_t act_len = data.len;
/* align up to four byte */
if (data.len % 4)
{
@@ -275,7 +276,7 @@ static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier
*pos.ptr = data.len/4 + 1;
pos = chunk_skip(pos, 1);
/* actual length in bytes */
- *(u_int16_t*)pos.ptr = htons(data.len);
+ *(u_int16_t*)pos.ptr = htons(act_len);
pos = chunk_skip(pos, sizeof(u_int16_t));
memcpy(pos.ptr, data.ptr, data.len);
pos = chunk_skip(pos, data.len);
@@ -697,8 +698,9 @@ static status_t initiate(private_eap_sim_t *this, eap_payload_t **out)
/**
* Implementation of eap_method_t.get_type.
*/
-static eap_type_t get_type(private_eap_sim_t *this)
+static eap_type_t get_type(private_eap_sim_t *this, u_int32_t *vendor)
{
+ *vendor = 0;
return EAP_SIM;
}
@@ -785,7 +787,7 @@ eap_sim_t *eap_create(eap_role_t role,
/* public functions */
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*))get_type;
+ 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;
diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c
index 6e2f73a43..6250604a6 100644
--- a/src/charon/sa/authenticators/eap_authenticator.c
+++ b/src/charon/sa/authenticators/eap_authenticator.c
@@ -138,7 +138,7 @@ static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init,
* Implementation of eap_authenticator_t.initiate
*/
static status_t initiate(private_eap_authenticator_t *this, eap_type_t type,
- eap_payload_t **out)
+ u_int32_t vendor, eap_payload_t **out)
{
/* if initiate() is called, role is always server */
this->role = EAP_SERVER;
@@ -151,21 +151,30 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type,
return FAILED;
}
- DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type);
- this->method = eap_method_create(type, this->role,
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "requesting vendor specific EAP authentication %d-%d",
+ type, vendor);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type);
+ }
+ this->method = eap_method_create(type, vendor, this->role,
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
if (this->method == NULL)
{
- DBG1(DBG_IKE, "configured EAP server method %N not supported, sending %N",
- eap_type_names, type, eap_code_names, EAP_FAILURE);
+
+ DBG1(DBG_IKE, "configured EAP server method not supported, sending %N",
+ eap_code_names, EAP_FAILURE);
*out = eap_payload_create_code(EAP_FAILURE);
return FAILED;
}
if (this->method->initiate(this->method, out) != NEED_MORE)
{
- DBG1(DBG_IKE, "failed to initiate %N, sending %N",
+ DBG1(DBG_IKE, "failed to initiate EAP exchange, sending %N",
eap_type_names, type, eap_code_names, EAP_FAILURE);
*out = eap_payload_create_code(EAP_FAILURE);
return FAILED;
@@ -179,11 +188,14 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type,
static status_t process_peer(private_eap_authenticator_t *this,
eap_payload_t *in, eap_payload_t **out)
{
- eap_type_t type = in->get_type(in);
+ eap_type_t type;
+ u_int32_t vendor;
- if (type == EAP_IDENTITY)
+ type = in->get_type(in, &vendor);
+
+ if (!vendor && type == EAP_IDENTITY)
{
- eap_method_t *method = eap_method_create(type, EAP_PEER,
+ eap_method_t *method = eap_method_create(type, 0, EAP_PEER,
this->ike_sa->get_other_id(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa));
@@ -205,32 +217,57 @@ static status_t process_peer(private_eap_authenticator_t *this,
/* create an eap_method for the first call */
if (this->method == NULL)
{
- DBG1(DBG_IKE, "EAP server requested %N authentication",
- eap_type_names, type);
- this->method = eap_method_create(type, EAP_PEER,
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "EAP server requested vendor specific EAP method %d-%d",
+ type, vendor);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "EAP server requested %N authentication",
+ eap_type_names, type);
+ }
+ this->method = eap_method_create(type, vendor, EAP_PEER,
this->ike_sa->get_other_id(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa));
if (this->method == NULL)
{
DBG1(DBG_IKE, "EAP server requested unsupported "
- "EAP method %N, sending EAP_NAK", eap_type_names, type);
+ "EAP method, sending EAP_NAK");
*out = eap_payload_create_nak();
return NEED_MORE;
}
}
+ type = this->method->get_type(this->method, &vendor);
+
switch (this->method->process(this->method, in, out))
{
case NEED_MORE:
return NEED_MORE;
case SUCCESS:
- DBG1(DBG_IKE, "EAP method %N succeded",
- eap_type_names, this->method->get_type(this->method));
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeded",
+ type, vendor);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "EAP method %N succeded", eap_type_names, type);
+ }
return SUCCESS;
case FAILED:
default:
- DBG1(DBG_IKE, "EAP method %N failed",
- eap_type_names, this->method->get_type(this->method));
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed",
+ type, vendor);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "EAP method %N failed",
+ eap_type_names, type);
+ }
return FAILED;
}
}
@@ -241,6 +278,11 @@ static status_t process_peer(private_eap_authenticator_t *this,
static status_t process_server(private_eap_authenticator_t *this,
eap_payload_t *in, eap_payload_t **out)
{
+ eap_type_t type;
+ u_int32_t vendor;
+
+ type = this->method->get_type(this->method, &vendor);
+
switch (this->method->process(this->method, in, out))
{
case NEED_MORE:
@@ -248,22 +290,35 @@ static status_t process_server(private_eap_authenticator_t *this,
case SUCCESS:
if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
{
- DBG1(DBG_IKE, "EAP method %N succeded, MSK established",
- eap_type_names, this->method->get_type(this->method));
this->msk = chunk_clone(this->msk);
}
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeded, "
+ "%sMSK established", type, vendor,
+ this->msk.ptr ? "" : "no ");
+ }
else
{
- DBG1(DBG_IKE, "EAP method %N succeded, no MSK established",
- eap_type_names, this->method->get_type(this->method));
+ DBG1(DBG_IKE, "EAP method %N succeded, %sMSK established",
+ eap_type_names, type, this->msk.ptr ? "" : "no ");
}
*out = eap_payload_create_code(EAP_SUCCESS);
return SUCCESS;
case FAILED:
default:
- DBG1(DBG_IKE, "EAP method %N failed for peer %D",
- eap_type_names, this->method->get_type(this->method),
- this->ike_sa->get_other_id(this->ike_sa));
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for "
+ "peer %D", type, vendor,
+ this->ike_sa->get_other_id(this->ike_sa));
+ }
+ else
+ {
+ DBG1(DBG_IKE, "EAP method %N failed for peer %D",
+ eap_type_names, type,
+ this->ike_sa->get_other_id(this->ike_sa));
+ }
*out = eap_payload_create_code(EAP_FAILURE);
return FAILED;
}
@@ -363,7 +418,7 @@ eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa)
this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
this->public.is_mutual = (bool(*)(eap_authenticator_t*))is_mutual;
- this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,eap_payload_t**))initiate;
+ this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,u_int32_t,eap_payload_t**))initiate;
this->public.process = (status_t(*)(eap_authenticator_t*,eap_payload_t*,eap_payload_t**))process;
/* private data */
diff --git a/src/charon/sa/authenticators/eap_authenticator.h b/src/charon/sa/authenticators/eap_authenticator.h
index 64a3267d7..cf2180ee3 100644
--- a/src/charon/sa/authenticators/eap_authenticator.h
+++ b/src/charon/sa/authenticators/eap_authenticator.h
@@ -105,15 +105,16 @@ struct eap_authenticator_t {
* this method. If initiate() returns NEED_MORE, the EAP authentication
* process started. In any case, a payload is created in "out".
*
- * @param this calling object
- * @param type EAP method to use to authenticate client
- * @param out created initiaal EAP message to send
+ * @param this calling object
+ * @param type EAP method to use to authenticate client
+ * @param vendor EAP vendor identifier, if type is vendor specific, or 0
+ * @param out created initiaal EAP message to send
* @return
* - FAILED, if initiation failed
* - NEED_MORE, if more EAP exchanges reqired
*/
status_t (*initiate) (eap_authenticator_t* this, eap_type_t type,
- eap_payload_t **out);
+ u_int32_t vendor, eap_payload_t **out);
/**
* @brief Process an EAP message.
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index 44f0298d5..b6c71a8b5 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -354,7 +354,7 @@ static void updown(private_child_sa_t *this, bool up)
up ? "up" : "down",
policy->my_ts->is_host(policy->my_ts,
this->me.addr) ? "-host" : "-client",
- this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
+ this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-v6",
this->config->get_name(this->config),
this->iface ? this->iface : "unknown",
this->reqid,
diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c
index d583e01bb..d0f3cde8d 100644
--- a/src/charon/sa/connect_manager.c
+++ b/src/charon/sa/connect_manager.c
@@ -32,13 +32,13 @@
#include <processing/jobs/initiate_mediation_job.h>
#include <encoding/payloads/endpoint_notify.h>
-// base timeout
-// the sending interval is P2P_INTERVAL * active checklists (N)
-// retransmission timeout is P2P_INTERVAL * N * checks in waiting state (NW)
-#define P2P_INTERVAL 20 // 20 ms
-// min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state)
-#define P2P_RTO_MIN 100 // 100 ms
-// max number of retransmissions (+ the initial check)
+/* base timeout
+ * the sending interval is P2P_INTERVAL * active checklists (N)
+ * retransmission timeout is P2P_INTERVAL * N * checks in waiting state (NW) */
+#define P2P_INTERVAL 20 /* ms */
+/* min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state) */
+#define P2P_RTO_MIN 100 /* ms */
+/* max number of retransmissions (+ the initial check) */
#define P2P_MAX_RETRANS 2
@@ -212,7 +212,8 @@ static void check_list_destroy(check_list_t *this)
DESTROY_OFFSET_IF(this->responder.endpoints, offsetof(endpoint_notify_t, destroy));
DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy);
- DESTROY_IF(this->triggered); // this list contains some of the same elements as contained in this->pairs
+ /* this list contains some of the same elements as contained in this->pairs */
+ DESTROY_IF(this->triggered);
free(this);
}
@@ -489,8 +490,6 @@ static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_
return this;
}
-// -----------------------------------------------------------------------------
-
/**
* Find an initiated connection by the peers' ids
*/
@@ -641,9 +640,6 @@ static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, endpoi
return status;
}
-// -----------------------------------------------------------------------------
-
-
/**
* Updates the state of the whole checklist
*/
@@ -659,7 +655,8 @@ static void update_checklist_state(check_list_t *checklist)
switch(current->state)
{
case CHECK_WAITING:
- // at least one is still waiting -> checklist remains in waiting state
+ /* at least one is still waiting -> checklist remains
+ * in waiting state */
iterator->destroy(iterator);
return;
case CHECK_IN_PROGRESS:
@@ -668,6 +665,8 @@ static void update_checklist_state(check_list_t *checklist)
case CHECK_SUCCEEDED:
succeeded = TRUE;
break;
+ default:
+ break;
}
}
iterator->destroy(iterator);
@@ -832,7 +831,6 @@ static void prune_pairs(linked_list_t *pairs)
{
iterator_t *iterator, *search;
endpoint_pair_t *current, *other;
- bool inserted = FALSE;
u_int32_t id = 0;
iterator = pairs->create_iterator(pairs, TRUE);
@@ -851,10 +849,10 @@ static void prune_pairs(linked_list_t *pairs)
if (current->local->equals(current->local, other->local) &&
current->remote->equals(current->remote, other->remote))
{
- // since the list of pairs is sorted by priority in descending
- // order, and we iterate the list from the beginning, we are
- // sure that the priority of 'other' is lower than that of
- // 'current', remove it
+ /* since the list of pairs is sorted by priority in descending
+ * order, and we iterate the list from the beginning, we are
+ * sure that the priority of 'other' is lower than that of
+ * 'current', remove it */
DBG1(DBG_IKE, "pruning endpoint pair %H - %H with priority %d",
other->local, other->remote, other->priority);
search->remove(search);
@@ -896,8 +894,6 @@ static void build_pairs(check_list_t *checklist)
prune_pairs(checklist->pairs);
}
-// -----------------------------------------------------------------------------
-
/**
* Processes the payloads of a connectivity check and returns the extracted data
*/
@@ -936,7 +932,7 @@ static status_t process_payloads(message_t *message, check_t *check)
}
check->endpoint = endpoint;
check->endpoint_raw = chunk_clone(notify->get_notification_data(notify));
- DBG3(DBG_IKE, "received P2P_ENDPOINT notify");
+ DBG2(DBG_IKE, "received P2P_ENDPOINT notify");
break;
}
case P2P_SESSIONID:
@@ -1000,9 +996,6 @@ static chunk_t build_signature(private_connect_manager_t *this,
return sig_hash;
}
-// -----------------------------------------------------------------------------
-
-// forward declarations
static void queue_retransmission(private_connect_manager_t *this, chunk_t session_id, u_int32_t mid);
static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time);
static void finish_checks(private_connect_manager_t *this, check_list_t *checklist);
@@ -1061,11 +1054,13 @@ retransmit_end:
case CHECK_FAILED:
finish_checks(this, checklist);
break;
+ default:
+ break;
}
pthread_mutex_unlock(&(this->mutex));
- // we reschedule it manually
+ /* we reschedule it manually */
return JOB_REQUEUE_NONE;
}
@@ -1192,13 +1187,13 @@ static job_requeue_t sender(sender_data_t *data)
check_destroy(check);
- // schedule this job again
+ /* schedule this job again */
u_int32_t N = this->checklists->get_count(this->checklists);
schedule_checks(this, checklist, P2P_INTERVAL * N);
pthread_mutex_unlock(&(this->mutex));
- // we reschedule it manually
+ /* we reschedule it manually */
return JOB_REQUEUE_NONE;
}
@@ -1240,8 +1235,10 @@ static job_requeue_t initiate_mediated(initiate_data_t *data)
}
else
{
- // this should (can?) not happen
+ /* this should (can?) not happen */
}
+
+ return JOB_REQUEUE_NONE;
}
/**
@@ -1270,9 +1267,10 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli
}
}
- //remove_checklist(this, checklist);
- //check_list_destroy(checklist);
- // FIXME: we should do this ^^^ after a specific timeout on the responder side
+ /* remove_checklist(this, checklist);
+ * check_list_destroy(checklist);
+ * FIXME: we should do this ^^^ after a specific timeout on the
+ * responder side */
}
/**
@@ -1313,6 +1311,8 @@ static void process_response(private_connect_manager_t *this, check_t *check,
case CHECK_FAILED:
finish_checks(this, checklist);
break;
+ default:
+ break;
}
}
else
@@ -1343,16 +1343,16 @@ static void process_request(private_connect_manager_t *this, check_t *check,
switch(pair->state)
{
case CHECK_IN_PROGRESS:
- pair->retransmitted = P2P_MAX_RETRANS; // prevent retransmissions
- // FIXME: we should wait to the next rto to send the triggered check
- // fall-through
+ /* prevent retransmissions */
+ pair->retransmitted = P2P_MAX_RETRANS;
+ /* FIXME: we should wait to the next rto to send the triggered check
+ * fall-through */
case CHECK_WAITING:
case CHECK_FAILED:
queue_triggered_check(checklist, pair);
break;
case CHECK_SUCCEEDED:
default:
- // do nothing
break;
}
}
@@ -1451,8 +1451,6 @@ static void process_check(private_connect_manager_t *this, message_t *message)
check_destroy(check);
}
-// -----------------------------------------------------------------------------
-
/**
* Implementation of connect_manager_t.check_and_register.
*/
@@ -1568,7 +1566,8 @@ static status_t set_responder_data(private_connect_manager_t *this,
build_pairs(checklist);
- schedule_checks(this, checklist, 0); // send the first check immediately
+ /* send the first check immediately */
+ schedule_checks(this, checklist, 0);
pthread_mutex_unlock(&(this->mutex));
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index 9d7a17e89..9cada2cb5 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -51,6 +51,7 @@
#include <sa/tasks/ike_natd.h>
#include <sa/tasks/ike_mobike.h>
#include <sa/tasks/ike_auth.h>
+#include <sa/tasks/ike_auth_lifetime.h>
#include <sa/tasks/ike_config.h>
#include <sa/tasks/ike_cert.h>
#include <sa/tasks/ike_rekey.h>
@@ -68,6 +69,7 @@
#ifdef P2P
#include <sa/tasks/ike_p2p.h>
+#include <processing/jobs/initiate_mediation_job.h>
#endif
#ifndef RESOLV_CONF
@@ -248,6 +250,8 @@ struct private_ike_sa_t {
u_int32_t established;
/** when IKE_SA gets rekeyed */
u_int32_t rekey;
+ /** when IKE_SA gets reauthenticated */
+ u_int32_t reauth;
/** when IKE_SA gets deleted */
u_int32_t delete;
} time;
@@ -256,6 +260,11 @@ struct private_ike_sa_t {
* how many times we have retried so far (keyingtries)
*/
u_int32_t keyingtry;
+
+ /**
+ * are we the initiator of this IKE_SA (rekeying does not affect this flag)
+ */
+ bool ike_initiator;
};
/**
@@ -307,16 +316,31 @@ static char *get_name(private_ike_sa_t *this)
return "(unnamed)";
}
-
/**
- * Implementation of ike_sa_t.get_stats.
+ * Implementation of ike_sa_t.get_statistic.
*/
-static void get_stats(private_ike_sa_t *this, u_int32_t *next_rekeying)
+static u_int32_t get_statistic(private_ike_sa_t *this, statistic_t kind)
{
- if (next_rekeying)
+ time_t now = time(NULL);
+
+ switch (kind)
{
- *next_rekeying = this->time.rekey;
+ case STAT_REKEY_TIME:
+ if (this->time.rekey > now)
+ {
+ return this->time.rekey - now;
+ }
+ break;
+ case STAT_REAUTH_TIME:
+ if (this->time.reauth > now)
+ {
+ return this->time.reauth - now;
+ }
+ break;
+ default:
+ break;
}
+ return 0;
}
/**
@@ -493,10 +517,6 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition,
this->conditions |= condition;
switch (condition)
{
- case COND_STALE:
- DBG1(DBG_IKE, "no route to %H, setting IKE_SA to stale",
- this->other_host);
- break;
case COND_NAT_HERE:
DBG1(DBG_IKE, "local host is behind NAT, sending keep alives");
this->conditions |= COND_NAT_ANY;
@@ -519,9 +539,6 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition,
this->conditions &= ~condition;
switch (condition)
{
- case COND_STALE:
- DBG1(DBG_IKE, "new route to %H found", this->other_host);
- break;
case COND_NAT_HERE:
case COND_NAT_FAKE:
case COND_NAT_THERE:
@@ -610,36 +627,58 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
if (this->state == IKE_CONNECTING)
{
job_t *job;
- u_int32_t now = time(NULL);
- u_int32_t soft, hard;
- bool reauth;
+ u_int32_t t;
- this->time.established = now;
- /* start DPD checks */
- send_dpd(this);
+ /* calculate rekey, reauth and lifetime */
+ this->time.established = time(NULL);
- /* schedule rekeying/reauthentication */
- soft = this->peer_cfg->get_lifetime(this->peer_cfg, TRUE);
- hard = this->peer_cfg->get_lifetime(this->peer_cfg, FALSE);
- reauth = this->peer_cfg->use_reauth(this->peer_cfg);
- DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
- reauth ? "reauthentication": "rekeying", soft, hard);
-
- if (soft)
+ /* schedule rekeying if we have a time which is smaller than
+ * an already scheduled rekeying */
+ t = this->peer_cfg->get_rekey_time(this->peer_cfg);
+ if (t && (this->time.rekey == 0 ||
+ (this->time.rekey > t + this->time.established)))
{
- this->time.rekey = now + soft;
- job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
- charon->scheduler->schedule_job(charon->scheduler, job,
- soft * 1000);
+ this->time.rekey = t + this->time.established;
+ job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, FALSE);
+ charon->scheduler->schedule_job(charon->scheduler,
+ job, t * 1000);
+ DBG1(DBG_IKE, "scheduling rekeying in %ds", t);
}
-
- if (hard)
+ t = this->peer_cfg->get_reauth_time(this->peer_cfg);
+ if (t && (this->time.reauth == 0 ||
+ (this->time.reauth > t + this->time.established)))
{
- this->time.delete = now + hard;
+ this->time.reauth = t + this->time.established;
+ job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE);
+ charon->scheduler->schedule_job(charon->scheduler,
+ job, t * 1000);
+ DBG1(DBG_IKE, "scheduling reauthentication in %ds", t);
+ }
+ t = this->peer_cfg->get_over_time(this->peer_cfg);
+ if (this->time.rekey || this->time.reauth)
+ {
+ if (this->time.reauth == 0)
+ {
+ this->time.delete = this->time.rekey;
+ }
+ else if (this->time.rekey == 0)
+ {
+ this->time.delete = this->time.reauth;
+ }
+ else
+ {
+ this->time.delete = min(this->time.rekey, this->time.reauth);
+ }
+ this->time.delete += t;
+ t = this->time.delete - this->time.established;
job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
charon->scheduler->schedule_job(charon->scheduler, job,
- hard * 1000);
+ t * 1000);
+ DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t);
}
+
+ /* start DPD checks */
+ send_dpd(this);
}
break;
}
@@ -681,17 +720,17 @@ static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
{
if (local)
{
- if (this->my_virtual_ip)
- {
- DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
- charon->kernel_interface->del_ip(charon->kernel_interface,
- this->my_virtual_ip);
- this->my_virtual_ip->destroy(this->my_virtual_ip);
- }
DBG1(DBG_IKE, "installing new virtual IP %H", ip);
if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
this->my_host) == SUCCESS)
{
+ if (this->my_virtual_ip)
+ {
+ DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
+ charon->kernel_interface->del_ip(charon->kernel_interface,
+ this->my_virtual_ip);
+ }
+ DESTROY_IF(this->my_virtual_ip);
this->my_virtual_ip = ip->clone(ip);
}
else
@@ -859,6 +898,8 @@ static void send_notify_response(private_ike_sa_t *this, message_t *request,
this->other_host = request->get_source(request);
this->other_host = this->other_host->clone(this->other_host);
}
+ response->set_source(response, this->my_host->clone(this->my_host));
+ response->set_destination(response, this->other_host->clone(this->other_host));
if (generate_message(this, response, &packet) == SUCCESS)
{
charon->sender->send(charon->sender, packet);
@@ -973,6 +1014,8 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
return DESTROY_ME;
}
+ this->ike_initiator = TRUE;
+
task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_natd_create(&this->public, TRUE);
@@ -983,6 +1026,8 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
if (this->peer_cfg->use_mobike(this->peer_cfg))
{
task = (task_t*)ike_mobike_create(&this->public, TRUE);
@@ -997,7 +1042,7 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
#ifdef P2P
if (this->peer_cfg->get_mediated_by(this->peer_cfg))
{
- // mediated connection, initiate mediation process
+ /* mediated connection, initiate mediation process */
job_t *job = (job_t*)initiate_mediation_job_create(this->ike_sa_id, child_cfg);
child_cfg->destroy(child_cfg);
charon->processor->queue_job(charon->processor, job);
@@ -1006,14 +1051,14 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
else if (this->peer_cfg->is_mediation(this->peer_cfg))
{
if (this->state == IKE_ESTABLISHED)
- {// FIXME: we should try to find a better solution to this
+ { /* FIXME: we should try to find a better solution to this */
SIG(CHILD_UP_SUCCESS, "mediation connection is already up and running");
}
}
else
#endif /* P2P */
{
- // normal IKE_SA with CHILD_SA
+ /* normal IKE_SA with CHILD_SA */
task = (task_t*)child_create_create(&this->public, child_cfg);
child_cfg->destroy(child_cfg);
this->task_manager->queue_task(this->task_manager, task);
@@ -1026,7 +1071,7 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
* Implementation of ike_sa_t.acquire.
*/
static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
-{// FIXME: P2P-NAT-T
+{ /* FIXME: P2P-NAT-T */
child_cfg_t *child_cfg;
iterator_t *iterator;
child_sa_t *current, *child_sa = NULL;
@@ -1073,6 +1118,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
if (this->peer_cfg->use_mobike(this->peer_cfg))
{
task = (task_t*)ike_mobike_create(&this->public, TRUE);
@@ -1350,7 +1397,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
* Implementation of ike_sa_t.retransmit.
*/
static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
-{// FIXME: P2P-NAT-T
+{ /* FIXME: P2P-NAT-T */
this->time.outbound = time(NULL);
if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
{
@@ -1467,6 +1514,8 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
task = (task_t*)child_create_create(&new->public, child_cfg);
new->task_manager->queue_task(new->task_manager, task);
}
+ task = (task_t*)ike_auth_lifetime_create(&new->public, TRUE);
+ new->task_manager->queue_task(new->task_manager, task);
if (this->peer_cfg->use_mobike(this->peer_cfg))
{
task = (task_t*)ike_mobike_create(&new->public, TRUE);
@@ -1900,14 +1949,59 @@ static status_t rekey(private_ike_sa_t *this)
static status_t reestablish(private_ike_sa_t *this)
{
task_t *task;
-
+
+ /* we can't reauthenticate as responder when we use EAP or virtual IPs.
+ * If the peer does not support RFC4478, there is no way to keep the
+ * IKE_SA up. */
+ if (!this->ike_initiator)
+ {
+ DBG1(DBG_IKE, "initiator did not reauthenticate as requested");
+ if (this->other_virtual_ip != NULL ||
+ has_condition(this, COND_EAP_AUTHENTICATED))
+ {
+ time_t now = time(NULL);
+
+ DBG1(DBG_IKE, "IKE_SA will timeout in %#V", &now, &this->time.delete);
+ return FAILED;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "reauthenticating actively");
+ }
+ }
task = (task_t*)ike_reauth_create(&this->public);
this->task_manager->queue_task(this->task_manager, task);
-
+
return this->task_manager->initiate(this->task_manager);
}
/**
+ * Implementation of ike_sa_t.set_auth_lifetime.
+ */
+static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime)
+{
+ job_t *job;
+ u_int32_t reduction = this->peer_cfg->get_over_time(this->peer_cfg);
+
+ this->time.reauth = time(NULL) + lifetime - reduction;
+ job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE);
+
+ if (lifetime < reduction)
+ {
+ DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication",
+ lifetime);
+ charon->processor->queue_job(charon->processor, job);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication"
+ " in %ds", lifetime, lifetime - reduction);
+ charon->scheduler->schedule_job(charon->scheduler, job,
+ (lifetime - reduction) * 1000);
+ }
+}
+
+/**
* Implementation of ike_sa_t.roam.
*/
static status_t roam(private_ike_sa_t *this, bool address)
@@ -1933,7 +2027,6 @@ static status_t roam(private_ike_sa_t *this, bool address)
me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
other);
- set_condition(this, COND_STALE, FALSE);
if (me)
{
if (me->ip_equals(me, this->my_host) &&
@@ -1977,6 +2070,7 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other)
this->other_host = other->other_host->clone(other->other_host);
this->my_id = other->my_id->clone(other->my_id);
this->other_id = other->other_id->clone(other->other_id);
+ this->ike_initiator = other->ike_initiator;
/* apply virtual assigned IPs... */
if (other->my_virtual_ip)
@@ -2007,6 +2101,24 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other)
/* move pending tasks to the new IKE_SA */
this->task_manager->adopt_tasks(this->task_manager, other->task_manager);
+ /* reauthentication timeout survives a rekeying */
+ if (other->time.reauth)
+ {
+ time_t reauth, delete, now = time(NULL);
+
+ this->time.reauth = other->time.reauth;
+ reauth = this->time.reauth - now;
+ delete = reauth + this->peer_cfg->get_over_time(this->peer_cfg);
+ this->time.delete = this->time.reauth + delete;
+ DBG1(DBG_IKE, "rescheduling reauthentication in %ds after rekeying, "
+ "lifetime reduced to %ds", reauth, delete);
+ charon->scheduler->schedule_job(charon->scheduler,
+ (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE),
+ reauth * 1000);
+ charon->scheduler->schedule_job(charon->scheduler,
+ (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE),
+ delete * 1000);
+ }
/* we have to initate here, there may be new tasks to handle */
return this->task_manager->initiate(this->task_manager);
}
@@ -2177,7 +2289,7 @@ static void destroy(private_ike_sa_t *this)
if (this->peer_cfg && this->peer_cfg->is_mediation(this->peer_cfg) &&
!this->ike_sa_id->is_initiator(this->ike_sa_id))
{
- // mediation server
+ /* mediation server */
charon->mediation_manager->remove(charon->mediation_manager, this->ike_sa_id);
}
DESTROY_IF(this->server_reflexive_host);
@@ -2207,8 +2319,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
/* Public functions */
this->public.get_state = (ike_sa_state_t (*)(ike_sa_t*)) get_state;
this->public.set_state = (void (*)(ike_sa_t*,ike_sa_state_t)) set_state;
- this->public.get_stats = (void (*)(ike_sa_t*,u_int32_t*))get_stats;
this->public.get_name = (char* (*)(ike_sa_t*))get_name;
+ this->public.get_statistic = (u_int32_t(*)(ike_sa_t*, statistic_t kind))get_statistic;
this->public.process_message = (status_t (*)(ike_sa_t*, message_t*)) process_message;
this->public.initiate = (status_t (*)(ike_sa_t*,child_cfg_t*)) initiate;
this->public.route = (status_t (*)(ike_sa_t*,child_cfg_t*)) route;
@@ -2256,6 +2368,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
this->public.rekey = (status_t (*)(ike_sa_t*))rekey;
this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish;
+ this->public.set_auth_lifetime = (void(*)(ike_sa_t*, u_int32_t lifetime))set_auth_lifetime;
this->public.roam = (status_t(*)(ike_sa_t*,bool))roam;
this->public.inherit = (status_t (*)(ike_sa_t*,ike_sa_t*))inherit;
this->public.generate_message = (status_t (*)(ike_sa_t*,message_t*,packet_t**))generate_message;
@@ -2296,6 +2409,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->time.inbound = this->time.outbound = time(NULL);
this->time.established = 0;
this->time.rekey = 0;
+ this->time.reauth = 0;
this->time.delete = 0;
this->ike_cfg = NULL;
this->peer_cfg = NULL;
@@ -2307,6 +2421,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->additional_addresses = linked_list_create();
this->pending_updates = 0;
this->keyingtry = 0;
+ this->ike_initiator = FALSE;
#ifdef P2P
this->server_reflexive_host = NULL;
#endif /* P2P */
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index 99f09e98a..975447d9c 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -29,6 +29,7 @@
typedef enum ike_extension_t ike_extension_t;
typedef enum ike_condition_t ike_condition_t;
typedef enum ike_sa_state_t ike_sa_state_t;
+typedef enum statistic_t statistic_t;
typedef struct ike_sa_t ike_sa_t;
#include <library.h>
@@ -115,9 +116,25 @@ enum ike_condition_t {
COND_NAT_FAKE = (1<<3),
/**
- * peer is currently not reachable (due missing route, ...)
+ * peer has ben authenticated using EAP
*/
- COND_STALE = (1<<4),
+ COND_EAP_AUTHENTICATED = (1<<4),
+};
+
+/**
+ * Information and statistics to query from an SA
+ */
+enum statistic_t {
+
+ /**
+ * Relative time for scheduled rekeying
+ */
+ STAT_REKEY_TIME,
+
+ /**
+ * Relative time for scheduled reauthentication
+ */
+ STAT_REAUTH_TIME,
};
/**
@@ -234,13 +251,6 @@ struct ike_sa_t {
ike_sa_state_t (*get_state) (ike_sa_t *this);
/**
- * @brief Get some statistics about this IKE_SA.
- *
- * @param next_rekeying when the next rekeying is scheduled
- */
- void (*get_stats)(ike_sa_t *this, u_int32_t *next_rekeying);
-
- /**
* @brief Set the state of the IKE_SA.
*
* @param this calling object
@@ -257,6 +267,15 @@ struct ike_sa_t {
char* (*get_name) (ike_sa_t *this);
/**
+ * @brief Get statistic values from the IKE_SA.
+ *
+ * @param this calling object
+ * @param kind kind of requested value
+ * @return value as integer
+ */
+ u_int32_t (*get_statistic)(ike_sa_t *this, statistic_t kind);
+
+ /**
* @brief Get the own host address.
*
* @param this calling object
@@ -846,6 +865,14 @@ struct ike_sa_t {
status_t (*reestablish) (ike_sa_t *this);
/**
+ * @brief Set the lifetime limit received from a AUTH_LIFETIME notify.
+ *
+ * @param this calling object
+ * @param lifetime lifetime in seconds
+ */
+ void (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime);
+
+ /**
* @brief Set the virtual IP to use for this IKE_SA and its children.
*
* The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
diff --git a/src/charon/sa/mediation_manager.c b/src/charon/sa/mediation_manager.c
index fca53a940..f6137304d 100644
--- a/src/charon/sa/mediation_manager.c
+++ b/src/charon/sa/mediation_manager.c
@@ -240,7 +240,7 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe
DBG2(DBG_IKE, "changing registered IKE_SA ID of peer '%D'", peer_id);
peer->ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL;
- // send callbacks to registered peers
+ /* send callbacks to registered peers */
identification_t *requester;
while(peer->requested_by->remove_last(peer->requested_by, (void**)&requester) == SUCCESS)
{
@@ -295,7 +295,7 @@ static ike_sa_id_t *check_and_register(private_mediation_manager_t *this,
if (!peer->ike_sa_id)
{
- // the peer is not online
+ /* the peer is not online */
DBG2(DBG_IKE, "requested peer '%D' is offline, registering peer '%D'", peer_id, requester);
register_peer(peer, requester);
pthread_mutex_unlock(&(this->mutex));
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
index f4484774e..89f527aba 100644
--- a/src/charon/sa/task_manager.c
+++ b/src/charon/sa/task_manager.c
@@ -30,6 +30,7 @@
#include <sa/tasks/ike_natd.h>
#include <sa/tasks/ike_mobike.h>
#include <sa/tasks/ike_auth.h>
+#include <sa/tasks/ike_auth_lifetime.h>
#include <sa/tasks/ike_cert.h>
#include <sa/tasks/ike_rekey.h>
#include <sa/tasks/ike_delete.h>
@@ -338,6 +339,7 @@ static status_t build_request(private_task_manager_t *this)
activate_task(this, IKE_AUTHENTICATE);
activate_task(this, IKE_CONFIG);
activate_task(this, CHILD_CREATE);
+ activate_task(this, IKE_AUTH_LIFETIME);
activate_task(this, IKE_MOBIKE);
}
break;
@@ -690,19 +692,21 @@ static status_t process_request(private_task_manager_t *this,
#ifdef P2P
task = (task_t*)ike_p2p_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
-#endif /* P2P */
+#endif /* P2P */
task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_config_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)child_create_create(this->ike_sa, NULL);
this->passive_tasks->insert_last(this->passive_tasks, task);
+ task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_mobike_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
break;
}
case CREATE_CHILD_SA:
- {//FIXME: we should prevent this on mediation connections
+ { /* FIXME: we should prevent this on mediation connections */
bool notify_found = FALSE, ts_found = FALSE;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
@@ -772,8 +776,12 @@ static status_t process_request(private_task_manager_t *this,
case UNACCEPTABLE_ADDRESSES:
case UNEXPECTED_NAT_DETECTED:
case COOKIE2:
- task = (task_t*)ike_mobike_create(this->ike_sa,
- FALSE);
+ task = (task_t*)ike_mobike_create(
+ this->ike_sa, FALSE);
+ break;
+ case AUTH_LIFETIME:
+ task = (task_t*)ike_auth_lifetime_create(
+ this->ike_sa, FALSE);
break;
default:
break;
diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c
index a3cd6a2bc..de88a0abe 100644
--- a/src/charon/sa/tasks/ike_auth.c
+++ b/src/charon/sa/tasks/ike_auth.c
@@ -297,6 +297,7 @@ static status_t collect_other_init_data(private_ike_auth_t *this, message_t *mes
return NEED_MORE;
}
+
/**
* Implementation of task_t.build to create AUTH payload from EAP data
*/
@@ -520,6 +521,7 @@ static status_t process_r(private_ike_auth_t *this, message_t *message)
break;
case NOT_FOUND:
/* use EAP if no AUTH payload found */
+ this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, TRUE);
this->eap_auth = eap_authenticator_create(this->ike_sa);
break;
default:
@@ -546,6 +548,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
{
peer_cfg_t *config;
eap_type_t eap_type;
+ u_int32_t eap_vendor;
eap_payload_t *eap_payload;
status_t status;
@@ -590,10 +593,11 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
return FAILED;
}
-
+
/* initiate EAP authenitcation */
- eap_type = config->get_eap_type(config);
- status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_payload);
+ eap_type = config->get_eap_type(config, &eap_vendor);
+ status = this->eap_auth->initiate(this->eap_auth, eap_type,
+ eap_vendor, &eap_payload);
message->add_payload(message, (payload_t*)eap_payload);
if (status != NEED_MORE)
{
@@ -645,6 +649,12 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
case ADDITIONAL_IP6_ADDRESS:
/* handled in ike_mobike task */
break;
+ case AUTH_LIFETIME:
+ /* handled in ike_auth_lifetime task */
+ break;
+ case P2P_ENDPOINT:
+ /* handled in ike_p2p task */
+ break;
default:
{
if (type < 16383)
diff --git a/src/charon/sa/tasks/ike_auth_lifetime.c b/src/charon/sa/tasks/ike_auth_lifetime.c
new file mode 100644
index 000000000..9d37ec608
--- /dev/null
+++ b/src/charon/sa/tasks/ike_auth_lifetime.c
@@ -0,0 +1,200 @@
+/**
+ * @file ike_auth_lifetime.c
+ *
+ * @brief Implementation of the ike_auth_lifetime task.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 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 "ike_auth_lifetime.h"
+
+#include <daemon.h>
+#include <encoding/payloads/notify_payload.h>
+
+
+typedef struct private_ike_auth_lifetime_t private_ike_auth_lifetime_t;
+
+/**
+ * Private members of a ike_auth_lifetime_t task.
+ */
+struct private_ike_auth_lifetime_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_auth_lifetime_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * add the AUTH_LIFETIME notify to the message
+ */
+static void add_auth_lifetime(private_ike_auth_lifetime_t *this, message_t *message)
+{
+ chunk_t chunk;
+ u_int32_t lifetime;
+
+ lifetime = this->ike_sa->get_statistic(this->ike_sa, STAT_REAUTH_TIME);
+ if (lifetime)
+ {
+ chunk = chunk_from_thing(lifetime);
+ *(u_int32_t*)chunk.ptr = htonl(lifetime);
+ message->add_notify(message, FALSE, AUTH_LIFETIME, chunk);
+ }
+}
+
+/**
+ * read notifys from message and evaluate them
+ */
+static void process_payloads(private_ike_auth_lifetime_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+ notify_payload_t *notify;
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify = (notify_payload_t*)payload;
+ switch (notify->get_notify_type(notify))
+ {
+ case AUTH_LIFETIME:
+ {
+ chunk_t data = notify->get_notification_data(notify);
+ u_int32_t lifetime = ntohl(*(u_int32_t*)data.ptr);
+ this->ike_sa->set_auth_lifetime(this->ike_sa, lifetime);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_auth_lifetime_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == INFORMATIONAL)
+ {
+ add_auth_lifetime(this, message);
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_auth_lifetime_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == INFORMATIONAL)
+ {
+ process_payloads(this, message);
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_auth_lifetime_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
+ {
+ add_auth_lifetime(this, message);
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_auth_lifetime_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
+ {
+ process_payloads(this, message);
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_auth_lifetime_t *this)
+{
+ return IKE_AUTH_LIFETIME;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_auth_lifetime_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_sa = ike_sa;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_auth_lifetime_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_auth_lifetime_t *this = malloc_thing(private_ike_auth_lifetime_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+
+ return &this->public;
+}
+
diff --git a/src/charon/sa/tasks/ike_auth_lifetime.h b/src/charon/sa/tasks/ike_auth_lifetime.h
new file mode 100644
index 000000000..500b89d39
--- /dev/null
+++ b/src/charon/sa/tasks/ike_auth_lifetime.h
@@ -0,0 +1,61 @@
+/**
+ * @file ike_auth_lifetime.h
+ *
+ * @brief Interface ike_auth_lifetime_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef IKE_AUTH_LIFETIME_H_
+#define IKE_AUTH_LIFETIME_H_
+
+typedef struct ike_auth_lifetime_t ike_auth_lifetime_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type IKE_AUTH_LIFETIME, implements RFC4478.
+ *
+ * This task exchanges lifetimes for IKE_AUTH to force a client to
+ * reauthenticate before the responders lifetime reaches the limit.
+ *
+ * @b Constructors:
+ * - ike_auth_lifetime_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_auth_lifetime_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * @brief Create a new IKE_AUTH_LIFETIME task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param initiator TRUE if taks is initiated by us
+ * @return ike_auth_lifetime task to handle by the task_manager
+ */
+ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_MOBIKE_H_ */
+
diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c
index d1fc8c695..a53c243f0 100644
--- a/src/charon/sa/tasks/ike_mobike.c
+++ b/src/charon/sa/tasks/ike_mobike.c
@@ -287,7 +287,7 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet)
static status_t build_i(private_ike_mobike_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_AUTH &&
- message->get_payload(message, SECURITY_ASSOCIATION))
+ message->get_payload(message, ID_INITIATOR))
{
message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty);
build_address_list(this, message);
@@ -317,7 +317,7 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
static status_t process_r(private_ike_mobike_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_AUTH &&
- message->get_payload(message, SECURITY_ASSOCIATION))
+ message->get_payload(message, ID_INITIATOR))
{
process_payloads(this, message);
}
@@ -348,7 +348,7 @@ static status_t process_r(private_ike_mobike_t *this, message_t *message)
static status_t build_r(private_ike_mobike_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_AUTH &&
- message->get_payload(message, SECURITY_ASSOCIATION))
+ this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
{
if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
{
@@ -378,7 +378,7 @@ static status_t build_r(private_ike_mobike_t *this, message_t *message)
static status_t process_i(private_ike_mobike_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_AUTH &&
- message->get_payload(message, SECURITY_ASSOCIATION))
+ this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
{
process_payloads(this, message);
return SUCCESS;
diff --git a/src/charon/sa/tasks/ike_p2p.c b/src/charon/sa/tasks/ike_p2p.c
index de5a2e30e..84b88e16b 100644
--- a/src/charon/sa/tasks/ike_p2p.c
+++ b/src/charon/sa/tasks/ike_p2p.c
@@ -34,7 +34,7 @@
#define P2P_SESSIONID_LEN 8
#define P2P_SESSIONKEY_LEN 16
-// FIXME: proposed values
+/* FIXME: proposed values */
#define P2P_SESSIONID_MIN_LEN 4
#define P2P_SESSIONID_MAX_LEN 16
#define P2P_SESSIONKEY_MIN_LEN 8
@@ -119,8 +119,6 @@ struct private_ike_p2p_t {
};
-// -----------------------------------------------------------------------------
-
/**
* Adds a list of endpoints as notifies to a given message
*/
@@ -146,7 +144,7 @@ static void gather_and_add_endpoints(private_ike_p2p_t *this, message_t *message
host_t *addr, *host;
u_int16_t port;
- // get the port that is used to communicate with the ms
+ /* get the port that is used to communicate with the ms */
host = this->ike_sa->get_my_host(this->ike_sa);
port = host->get_port(host);
@@ -215,7 +213,8 @@ static void process_payloads(private_ike_p2p_t *this, message_t *message)
DBG1(DBG_IKE, "received invalid P2P_ENDPOINT notify");
break;
}
- DBG2(DBG_IKE, "received P2P_ENDPOINT notify");
+ DBG1(DBG_IKE, "received %N P2P_ENDPOINT %#H", p2p_endpoint_type_names,
+ endpoint->get_type(endpoint), endpoint->get_host(endpoint));
this->remote_endpoints->insert_last(this->remote_endpoints, endpoint);
break;
@@ -253,8 +252,6 @@ static void process_payloads(private_ike_p2p_t *this, message_t *message)
iterator->destroy(iterator);
}
-// -----------------------------------------------------------------------------
-
/**
* Implementation of task_t.process for initiator
*/
@@ -296,8 +293,8 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message)
if (!this->response)
{
- // only the initiator creates a session ID. the responder returns
- // the session ID that it received from the initiator
+ /* only the initiator creates a session ID. the responder returns
+ * the session ID that it received from the initiator */
if (rand->allocate_pseudo_random_bytes(rand,
P2P_SESSIONID_LEN, &this->session_id) != SUCCESS)
{
@@ -326,7 +323,7 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message)
}
else
{
- // FIXME: should we make that configurable
+ /* FIXME: should we make that configurable */
message->add_notify(message, FALSE, P2P_CALLBACK, chunk_empty);
}
@@ -334,8 +331,9 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message)
break;
}
+ default:
+ break;
}
-
return NEED_MORE;
}
@@ -387,11 +385,11 @@ static status_t process_r(private_ike_p2p_t *this, message_t *message)
}
DBG1(DBG_IKE, "received P2P_CONNECT");
-
break;
}
+ default:
+ break;
}
-
return NEED_MORE;
}
@@ -420,16 +418,16 @@ static status_t build_r(private_ike_p2p_t *this, message_t *message)
if (this->response)
{
- // FIXME: handle result of set_responder_data
- // as initiator, upon receiving a response from another peer,
- // update the checklist and start sending checks
+ /* FIXME: handle result of set_responder_data
+ * as initiator, upon receiving a response from another peer,
+ * update the checklist and start sending checks */
charon->connect_manager->set_responder_data(charon->connect_manager,
this->session_id, this->session_key, this->remote_endpoints);
}
else
{
- // FIXME: handle result of set_initiator_data
- // as responder, create a checklist with the initiator's data
+ /* FIXME: handle result of set_initiator_data
+ * as responder, create a checklist with the initiator's data */
charon->connect_manager->set_initiator_data(charon->connect_manager,
this->peer_id, this->ike_sa->get_my_id(this->ike_sa),
this->session_id, this->session_key, this->remote_endpoints,
@@ -440,9 +438,10 @@ static status_t build_r(private_ike_p2p_t *this, message_t *message)
return FAILED;
}
}
-
break;
}
+ default:
+ break;
}
return SUCCESS;
}
@@ -469,20 +468,19 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message)
case IKE_AUTH:
{
process_payloads(this, message);
-
- //FIXME: we should update the server reflexive endpoint somehow, if mobike notices a change
-
+ /* FIXME: we should update the server reflexive endpoint somehow,
+ * if mobike notices a change */
endpoint_notify_t *reflexive;
- if (this->remote_endpoints->get_first(this->remote_endpoints, (void**)&reflexive) == SUCCESS &&
- reflexive->get_type(reflexive) == SERVER_REFLEXIVE)
- {//FIXME: should we accept this endpoint even if we did not send a request?
+ if (this->remote_endpoints->get_first(this->remote_endpoints,
+ (void**)&reflexive) == SUCCESS &&
+ reflexive->get_type(reflexive) == SERVER_REFLEXIVE)
+ { /* FIXME: should we accept this endpoint even if we did not send
+ * a request? */
host_t *endpoint = reflexive->get_host(reflexive);
- DBG2(DBG_IKE, "received server reflexive endpoint %#H", endpoint);
this->ike_sa->set_server_reflexive_host(this->ike_sa, endpoint->clone(endpoint));
}
-
- // FIXME: what if it failed? e.g. AUTH failure
+ /* FIXME: what if it failed? e.g. AUTH failure */
SIG(CHILD_UP_SUCCESS, "established mediation connection without CHILD_SA successfully");
break;
@@ -494,22 +492,23 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message)
if (this->failed)
{
DBG1(DBG_IKE, "peer '%D' is not online", this->peer_id);
- // FIXME: notify the mediated connection (job?)
- // FIXME: probably delete the created checklist, at least as responder
+ /* FIXME: notify the mediated connection (job?)
+ * FIXME: probably delete the created checklist, at least as
+ * responder */
}
else
{
if (this->response)
{
- // FIXME: handle result of set_responder_data
- // as responder, we update the checklist and start sending checks
+ /* FIXME: handle result of set_responder_data.
+ * as responder, we update the checklist and start sending checks */
charon->connect_manager->set_responder_data(charon->connect_manager,
this->session_id, this->session_key, this->local_endpoints);
}
else
{
- // FIXME: handle result of set_initiator_data
- // as initiator, we create a checklist and set the initiator's data
+ /* FIXME: handle result of set_initiator_data
+ * as initiator, we create a checklist and set the initiator's data */
charon->connect_manager->set_initiator_data(charon->connect_manager,
this->ike_sa->get_my_id(this->ike_sa), this->peer_id,
this->session_id, this->session_key, this->local_endpoints,
@@ -518,12 +517,12 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message)
}
break;
}
+ default:
+ break;
}
return SUCCESS;
}
-// -----------------------------------------------------------------------------
-
/**
* Implementation of task_t.process for initiator (mediation server)
*/
@@ -542,21 +541,19 @@ static status_t build_i_ms(private_ike_p2p_t *this, message_t *message)
}
else
{
- notify_payload_t *notify;
-
if (this->response)
{
message->add_notify(message, FALSE, P2P_RESPONSE, chunk_empty);
- }
-
+ }
message->add_notify(message, FALSE, P2P_SESSIONID, this->session_id);
message->add_notify(message, FALSE, P2P_SESSIONKEY, this->session_key);
add_endpoints_to_message(message, this->remote_endpoints);
}
-
break;
}
+ default:
+ break;
}
return NEED_MORE;
@@ -614,9 +611,10 @@ static status_t process_r_ms(private_ike_p2p_t *this, message_t *message)
this->invalid_syntax = TRUE;
break;
}
-
break;
}
+ default:
+ break;
}
return NEED_MORE;
@@ -679,7 +677,7 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message)
if (!peer_sa)
{
- // the peer is not online
+ /* the peer is not online */
message->add_notify(message, TRUE, P2P_CONNECT_FAILED, chunk_empty);
break;
}
@@ -691,6 +689,8 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message)
break;
}
+ default:
+ break;
}
return SUCCESS;
}
@@ -700,18 +700,9 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message)
*/
static status_t process_i_ms(private_ike_p2p_t *this, message_t *message)
{
- switch(message->get_exchange_type(message))
- {
- case P2P_CONNECT:
- {
- break;
- }
- }
return SUCCESS;
}
-// -----------------------------------------------------------------------------
-
/**
* Implementation of ike_p2p.connect
*/
@@ -813,7 +804,7 @@ ike_p2p_t *ike_p2p_create(ike_sa_t *ike_sa, bool initiator)
}
else
{
- // mediation server
+ /* mediation server */
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_ms;
diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c
index e9d0c4da1..cc20a8861 100644
--- a/src/charon/sa/tasks/task.c
+++ b/src/charon/sa/tasks/task.c
@@ -28,6 +28,7 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
"IKE_NATD",
"IKE_MOBIKE",
"IKE_AUTHENTICATE",
+ "IKE_AUTH_LIFETIME",
"IKE_CERT",
"IKE_CONFIG",
"IKE_REKEY",
diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h
index dd2bb8a83..a59207711 100644
--- a/src/charon/sa/tasks/task.h
+++ b/src/charon/sa/tasks/task.h
@@ -45,6 +45,8 @@ enum task_type_t {
IKE_MOBIKE,
/** authenticate the initiated IKE_SA */
IKE_AUTHENTICATE,
+ /** AUTH_LIFETIME negotiation, RFC4478 */
+ IKE_AUTH_LIFETIME,
/** exchange certificates and requests */
IKE_CERT,
/** Configuration payloads, virtual IP and such */