diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-02-07 13:56:17 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-02-07 13:56:17 +0000 |
commit | bcc8f7ca7fd8e8ff6e8a4d579251458313133598 (patch) | |
tree | a86b42b486c954937b32ffeaaa725804cb1458ec /src/charon | |
parent | 49104abddf3d71d5abf5cf75dc7f95fa6c55fa63 (diff) | |
download | vyos-strongswan-bcc8f7ca7fd8e8ff6e8a4d579251458313133598.tar.gz vyos-strongswan-bcc8f7ca7fd8e8ff6e8a4d579251458313133598.zip |
[svn-upgrade] Integrating new upstream version, strongswan (4.1.10)
Diffstat (limited to 'src/charon')
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**)¤t)) + 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**)¤t)) + 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, - ¤t, &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, - ¤t, &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, - ¤t, &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 */ |