diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-07-05 00:05:56 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-07-05 00:05:56 +0000 |
commit | 5db544cc26db378616a46dfa22138f0008cf2930 (patch) | |
tree | ff9254d87967bb6f703a5ab5e63edcde2e8a6c17 /src | |
parent | 3d44c2edf1a3663c7d4acc4434bc8a3abace1ebf (diff) | |
download | vyos-strongswan-5db544cc26db378616a46dfa22138f0008cf2930.tar.gz vyos-strongswan-5db544cc26db378616a46dfa22138f0008cf2930.zip |
- Updated to new upstream release.
Diffstat (limited to 'src')
114 files changed, 5836 insertions, 4353 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 9fb649725..d9d363ab4 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -114,6 +114,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/_copyright/Makefile.in b/src/_copyright/Makefile.in index 68d2f0484..3b49498a3 100644 --- a/src/_copyright/Makefile.in +++ b/src/_copyright/Makefile.in @@ -130,6 +130,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/_updown/Makefile.in b/src/_updown/Makefile.in index 9118eef49..ff4651d05 100644 --- a/src/_updown/Makefile.in +++ b/src/_updown/Makefile.in @@ -113,6 +113,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/_updown/_updown b/src/_updown/_updown index 8db74f737..795b6f388 100755 --- a/src/_updown/_updown +++ b/src/_updown/_updown @@ -4,7 +4,7 @@ # Copyright (C) 2003-2004 Nigel Meteringham # Copyright (C) 2003-2004 Tuomo Soini # Copyright (C) 2002-2004 Michael Richardson -# Copyright (C) 2005-2006 Andreas Steffen <andreas.steffen@strongswan.org> +# Copyright (C) 2005-2007 Andreas Steffen <andreas.steffen@strongswan.org> # # 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 @@ -191,14 +191,6 @@ addsource() { doroute() { st=0 - parms="$PLUTO_PEER_CLIENT" - - parms2= - if [ -n "$PLUTO_NEXT_HOP" ] - then - parms2="via $PLUTO_NEXT_HOP" - fi - parms2="$parms2 dev $PLUTO_INTERFACE" if [ -z "$PLUTO_MY_SOURCEIP" ] then @@ -218,6 +210,26 @@ doroute() { fi fi + if [ -z "$KLIPS" -a -z "$PLUTO_MY_SOURCEIP" ] + then + # leave because no route entry is required + return $st + fi + + parms1="$PLUTO_PEER_CLIENT" + + parms2= + if [ -n "$KLIPS" ] + then + if [ -n "$PLUTO_NEXT_HOP" ] + then + parms2="via $PLUTO_NEXT_HOP" + fi + else + parms2="via $PLUTO_ME" + fi + parms2="$parms2 dev $PLUTO_INTERFACE" + parms3= if test "$1" = "add" -a -n "$PLUTO_MY_SOURCEIP" then @@ -233,7 +245,7 @@ doroute() { it="ip route $1 0.0.0.0/1 $parms2 $parms3 && ip route $1 128.0.0.0/1 $parms2 $parms3" ;; - *) it="ip route $1 $parms $parms2 $parms3" + *) it="ip route $1 $parms1 $parms2 $parms3" ;; esac oops="`eval $it 2>&1`" @@ -252,9 +264,11 @@ doroute() { # in the presence of KLIPS and ipsecN interfaces do not use IPSEC_POLICY if [ `echo "$PLUTO_INTERFACE" | grep "ipsec"` ] then + KLIPS=1 IPSEC_POLICY_IN="" IPSEC_POLICY_OUT="" else + KLIPS= IPSEC_POLICY="-m policy --pol ipsec --proto esp --reqid $PLUTO_REQID" IPSEC_POLICY_IN="$IPSEC_POLICY --dir in" IPSEC_POLICY_OUT="$IPSEC_POLICY --dir out" @@ -275,6 +289,13 @@ fi # the big choice case "$PLUTO_VERB:$1" in prepare-host:*|prepare-client:*) + if [ -z "$KLIPS" -a -z "$PLUTO_MY_SOURCEIP" ] + then + # exit because no route will be added, + # so that existing routes can stay + exit 0 + fi + # delete possibly-existing route (preliminary to adding a route) case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in "0.0.0.0/0.0.0.0") diff --git a/src/_updown_espmark/Makefile.in b/src/_updown_espmark/Makefile.in index da105b469..f2d3eadd6 100644 --- a/src/_updown_espmark/Makefile.in +++ b/src/_updown_espmark/Makefile.in @@ -113,6 +113,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index a64d9fa70..9812a32ae 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -48,20 +48,20 @@ 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/event_queue.c processing/event_queue.h \ -processing/job_queue.c processing/job_queue.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 processing/jobs/delete_child_sa_job.h \ processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \ -processing/jobs/job.c processing/jobs/job.h \ processing/jobs/process_message_job.c processing/jobs/process_message_job.h \ processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \ processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \ processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \ processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \ processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \ +processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/scheduler.c processing/scheduler.h \ -processing/thread_pool.c processing/thread_pool.h \ +processing/processor.c processing/processor.h \ sa/authenticators/authenticator.c sa/authenticators/authenticator.h \ sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \ sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ @@ -82,7 +82,9 @@ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ sa/tasks/ike_init.c sa/tasks/ike_init.h \ 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/task.c sa/tasks/task.h diff --git a/src/charon/Makefile.in b/src/charon/Makefile.in index 9f4177f60..1646eec6c 100644 --- a/src/charon/Makefile.in +++ b/src/charon/Makefile.in @@ -114,13 +114,12 @@ 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) event_queue.$(OBJEXT) job_queue.$(OBJEXT) \ - acquire_job.$(OBJEXT) delete_child_sa_job.$(OBJEXT) \ - delete_ike_sa_job.$(OBJEXT) job.$(OBJEXT) \ + socket.$(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) \ send_dpd_job.$(OBJEXT) send_keepalive_job.$(OBJEXT) \ - scheduler.$(OBJEXT) thread_pool.$(OBJEXT) \ + roam_job.$(OBJEXT) scheduler.$(OBJEXT) processor.$(OBJEXT) \ authenticator.$(OBJEXT) eap_authenticator.$(OBJEXT) \ eap_method.$(OBJEXT) psk_authenticator.$(OBJEXT) \ rsa_authenticator.$(OBJEXT) child_sa.$(OBJEXT) \ @@ -129,7 +128,8 @@ am_charon_OBJECTS = bus.$(OBJEXT) file_logger.$(OBJEXT) \ child_delete.$(OBJEXT) child_rekey.$(OBJEXT) \ ike_auth.$(OBJEXT) ike_cert.$(OBJEXT) ike_config.$(OBJEXT) \ ike_delete.$(OBJEXT) ike_dpd.$(OBJEXT) ike_init.$(OBJEXT) \ - ike_natd.$(OBJEXT) ike_rekey.$(OBJEXT) task.$(OBJEXT) + ike_natd.$(OBJEXT) ike_mobike.$(OBJEXT) ike_rekey.$(OBJEXT) \ + ike_reauth.$(OBJEXT) task.$(OBJEXT) charon_OBJECTS = $(am_charon_OBJECTS) charon_DEPENDENCIES = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ @@ -214,6 +214,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ @@ -344,20 +345,20 @@ 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/event_queue.c processing/event_queue.h \ -processing/job_queue.c processing/job_queue.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 processing/jobs/delete_child_sa_job.h \ processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \ -processing/jobs/job.c processing/jobs/job.h \ processing/jobs/process_message_job.c processing/jobs/process_message_job.h \ processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \ processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \ processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \ processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \ processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \ +processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/scheduler.c processing/scheduler.h \ -processing/thread_pool.c processing/thread_pool.h \ +processing/processor.c processing/processor.h \ sa/authenticators/authenticator.c sa/authenticators/authenticator.h \ sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \ sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ @@ -378,7 +379,9 @@ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ sa/tasks/ike_init.c sa/tasks/ike_init.h \ 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/task.c sa/tasks/task.h INCLUDES = -I${linuxdir} -I$(top_srcdir)/src/libstrongswan \ @@ -584,6 +587,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/authenticator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback_job.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cert_payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certreq_payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/child_cfg.Po@am__quote@ @@ -605,7 +609,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_sim.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encodings.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encryption_payload.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_logger.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_payload.Po@am__quote@ @@ -617,14 +620,14 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_dpd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_header.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_init.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_mobike.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_natd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_reauth.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_rekey.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa_id.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa_manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface_manager.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/job.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/job_queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ke_payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_backend.Plo@am__quote@ @@ -637,6 +640,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peer_cfg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process_message_job.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/processor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal_substructure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psk_authenticator.Po@am__quote@ @@ -644,6 +648,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rekey_child_sa_job.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rekey_ike_sa_job.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/retransmit_job.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/roam_job.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa_authenticator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sa_payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheduler.Po@am__quote@ @@ -655,7 +660,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_logger.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task_manager.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_pool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_selector.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_selector_substructure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform_attribute.Po@am__quote@ @@ -1316,34 +1320,6 @@ socket.obj: network/socket.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 socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi` -event_queue.o: processing/event_queue.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT event_queue.o -MD -MP -MF "$(DEPDIR)/event_queue.Tpo" -c -o event_queue.o `test -f 'processing/event_queue.c' || echo '$(srcdir)/'`processing/event_queue.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/event_queue.Tpo" "$(DEPDIR)/event_queue.Po"; else rm -f "$(DEPDIR)/event_queue.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/event_queue.c' object='event_queue.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 event_queue.o `test -f 'processing/event_queue.c' || echo '$(srcdir)/'`processing/event_queue.c - -event_queue.obj: processing/event_queue.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT event_queue.obj -MD -MP -MF "$(DEPDIR)/event_queue.Tpo" -c -o event_queue.obj `if test -f 'processing/event_queue.c'; then $(CYGPATH_W) 'processing/event_queue.c'; else $(CYGPATH_W) '$(srcdir)/processing/event_queue.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/event_queue.Tpo" "$(DEPDIR)/event_queue.Po"; else rm -f "$(DEPDIR)/event_queue.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/event_queue.c' object='event_queue.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 event_queue.obj `if test -f 'processing/event_queue.c'; then $(CYGPATH_W) 'processing/event_queue.c'; else $(CYGPATH_W) '$(srcdir)/processing/event_queue.c'; fi` - -job_queue.o: processing/job_queue.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job_queue.o -MD -MP -MF "$(DEPDIR)/job_queue.Tpo" -c -o job_queue.o `test -f 'processing/job_queue.c' || echo '$(srcdir)/'`processing/job_queue.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job_queue.Tpo" "$(DEPDIR)/job_queue.Po"; else rm -f "$(DEPDIR)/job_queue.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/job_queue.c' object='job_queue.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 job_queue.o `test -f 'processing/job_queue.c' || echo '$(srcdir)/'`processing/job_queue.c - -job_queue.obj: processing/job_queue.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job_queue.obj -MD -MP -MF "$(DEPDIR)/job_queue.Tpo" -c -o job_queue.obj `if test -f 'processing/job_queue.c'; then $(CYGPATH_W) 'processing/job_queue.c'; else $(CYGPATH_W) '$(srcdir)/processing/job_queue.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job_queue.Tpo" "$(DEPDIR)/job_queue.Po"; else rm -f "$(DEPDIR)/job_queue.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/job_queue.c' object='job_queue.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 job_queue.obj `if test -f 'processing/job_queue.c'; then $(CYGPATH_W) 'processing/job_queue.c'; else $(CYGPATH_W) '$(srcdir)/processing/job_queue.c'; fi` - acquire_job.o: processing/jobs/acquire_job.c @am__fastdepCC_TRUE@ if $(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@ then mv -f "$(DEPDIR)/acquire_job.Tpo" "$(DEPDIR)/acquire_job.Po"; else rm -f "$(DEPDIR)/acquire_job.Tpo"; exit 1; fi @@ -1358,6 +1334,20 @@ acquire_job.obj: processing/jobs/acquire_job.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 acquire_job.obj `if test -f 'processing/jobs/acquire_job.c'; then $(CYGPATH_W) 'processing/jobs/acquire_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/acquire_job.c'; fi` +callback_job.o: processing/jobs/callback_job.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT callback_job.o -MD -MP -MF "$(DEPDIR)/callback_job.Tpo" -c -o callback_job.o `test -f 'processing/jobs/callback_job.c' || echo '$(srcdir)/'`processing/jobs/callback_job.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/callback_job.Tpo" "$(DEPDIR)/callback_job.Po"; else rm -f "$(DEPDIR)/callback_job.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/callback_job.c' object='callback_job.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 callback_job.o `test -f 'processing/jobs/callback_job.c' || echo '$(srcdir)/'`processing/jobs/callback_job.c + +callback_job.obj: processing/jobs/callback_job.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT callback_job.obj -MD -MP -MF "$(DEPDIR)/callback_job.Tpo" -c -o callback_job.obj `if test -f 'processing/jobs/callback_job.c'; then $(CYGPATH_W) 'processing/jobs/callback_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/callback_job.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/callback_job.Tpo" "$(DEPDIR)/callback_job.Po"; else rm -f "$(DEPDIR)/callback_job.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/callback_job.c' object='callback_job.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 callback_job.obj `if test -f 'processing/jobs/callback_job.c'; then $(CYGPATH_W) 'processing/jobs/callback_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/callback_job.c'; fi` + delete_child_sa_job.o: processing/jobs/delete_child_sa_job.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT delete_child_sa_job.o -MD -MP -MF "$(DEPDIR)/delete_child_sa_job.Tpo" -c -o delete_child_sa_job.o `test -f 'processing/jobs/delete_child_sa_job.c' || echo '$(srcdir)/'`processing/jobs/delete_child_sa_job.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/delete_child_sa_job.Tpo" "$(DEPDIR)/delete_child_sa_job.Po"; else rm -f "$(DEPDIR)/delete_child_sa_job.Tpo"; exit 1; fi @@ -1386,20 +1376,6 @@ delete_ike_sa_job.obj: processing/jobs/delete_ike_sa_job.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 delete_ike_sa_job.obj `if test -f 'processing/jobs/delete_ike_sa_job.c'; then $(CYGPATH_W) 'processing/jobs/delete_ike_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/delete_ike_sa_job.c'; fi` -job.o: processing/jobs/job.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job.o -MD -MP -MF "$(DEPDIR)/job.Tpo" -c -o job.o `test -f 'processing/jobs/job.c' || echo '$(srcdir)/'`processing/jobs/job.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job.Tpo" "$(DEPDIR)/job.Po"; else rm -f "$(DEPDIR)/job.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/job.c' object='job.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 job.o `test -f 'processing/jobs/job.c' || echo '$(srcdir)/'`processing/jobs/job.c - -job.obj: processing/jobs/job.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job.obj -MD -MP -MF "$(DEPDIR)/job.Tpo" -c -o job.obj `if test -f 'processing/jobs/job.c'; then $(CYGPATH_W) 'processing/jobs/job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/job.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job.Tpo" "$(DEPDIR)/job.Po"; else rm -f "$(DEPDIR)/job.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/job.c' object='job.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 job.obj `if test -f 'processing/jobs/job.c'; then $(CYGPATH_W) 'processing/jobs/job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/job.c'; fi` - process_message_job.o: processing/jobs/process_message_job.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT process_message_job.o -MD -MP -MF "$(DEPDIR)/process_message_job.Tpo" -c -o process_message_job.o `test -f 'processing/jobs/process_message_job.c' || echo '$(srcdir)/'`processing/jobs/process_message_job.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/process_message_job.Tpo" "$(DEPDIR)/process_message_job.Po"; else rm -f "$(DEPDIR)/process_message_job.Tpo"; exit 1; fi @@ -1484,6 +1460,20 @@ send_keepalive_job.obj: processing/jobs/send_keepalive_job.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 send_keepalive_job.obj `if test -f 'processing/jobs/send_keepalive_job.c'; then $(CYGPATH_W) 'processing/jobs/send_keepalive_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/send_keepalive_job.c'; fi` +roam_job.o: processing/jobs/roam_job.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT roam_job.o -MD -MP -MF "$(DEPDIR)/roam_job.Tpo" -c -o roam_job.o `test -f 'processing/jobs/roam_job.c' || echo '$(srcdir)/'`processing/jobs/roam_job.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/roam_job.Tpo" "$(DEPDIR)/roam_job.Po"; else rm -f "$(DEPDIR)/roam_job.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/roam_job.c' object='roam_job.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 roam_job.o `test -f 'processing/jobs/roam_job.c' || echo '$(srcdir)/'`processing/jobs/roam_job.c + +roam_job.obj: processing/jobs/roam_job.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT roam_job.obj -MD -MP -MF "$(DEPDIR)/roam_job.Tpo" -c -o roam_job.obj `if test -f 'processing/jobs/roam_job.c'; then $(CYGPATH_W) 'processing/jobs/roam_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/roam_job.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/roam_job.Tpo" "$(DEPDIR)/roam_job.Po"; else rm -f "$(DEPDIR)/roam_job.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/roam_job.c' object='roam_job.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 roam_job.obj `if test -f 'processing/jobs/roam_job.c'; then $(CYGPATH_W) 'processing/jobs/roam_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/roam_job.c'; fi` + scheduler.o: processing/scheduler.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT scheduler.o -MD -MP -MF "$(DEPDIR)/scheduler.Tpo" -c -o scheduler.o `test -f 'processing/scheduler.c' || echo '$(srcdir)/'`processing/scheduler.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/scheduler.Tpo" "$(DEPDIR)/scheduler.Po"; else rm -f "$(DEPDIR)/scheduler.Tpo"; exit 1; fi @@ -1498,19 +1488,19 @@ scheduler.obj: processing/scheduler.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 scheduler.obj `if test -f 'processing/scheduler.c'; then $(CYGPATH_W) 'processing/scheduler.c'; else $(CYGPATH_W) '$(srcdir)/processing/scheduler.c'; fi` -thread_pool.o: processing/thread_pool.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread_pool.o -MD -MP -MF "$(DEPDIR)/thread_pool.Tpo" -c -o thread_pool.o `test -f 'processing/thread_pool.c' || echo '$(srcdir)/'`processing/thread_pool.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/thread_pool.Tpo" "$(DEPDIR)/thread_pool.Po"; else rm -f "$(DEPDIR)/thread_pool.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/thread_pool.c' object='thread_pool.o' libtool=no @AMDEPBACKSLASH@ +processor.o: processing/processor.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT processor.o -MD -MP -MF "$(DEPDIR)/processor.Tpo" -c -o processor.o `test -f 'processing/processor.c' || echo '$(srcdir)/'`processing/processor.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/processor.Tpo" "$(DEPDIR)/processor.Po"; else rm -f "$(DEPDIR)/processor.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/processor.c' object='processor.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 thread_pool.o `test -f 'processing/thread_pool.c' || echo '$(srcdir)/'`processing/thread_pool.c +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o processor.o `test -f 'processing/processor.c' || echo '$(srcdir)/'`processing/processor.c -thread_pool.obj: processing/thread_pool.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread_pool.obj -MD -MP -MF "$(DEPDIR)/thread_pool.Tpo" -c -o thread_pool.obj `if test -f 'processing/thread_pool.c'; then $(CYGPATH_W) 'processing/thread_pool.c'; else $(CYGPATH_W) '$(srcdir)/processing/thread_pool.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/thread_pool.Tpo" "$(DEPDIR)/thread_pool.Po"; else rm -f "$(DEPDIR)/thread_pool.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/thread_pool.c' object='thread_pool.obj' libtool=no @AMDEPBACKSLASH@ +processor.obj: processing/processor.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT processor.obj -MD -MP -MF "$(DEPDIR)/processor.Tpo" -c -o processor.obj `if test -f 'processing/processor.c'; then $(CYGPATH_W) 'processing/processor.c'; else $(CYGPATH_W) '$(srcdir)/processing/processor.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/processor.Tpo" "$(DEPDIR)/processor.Po"; else rm -f "$(DEPDIR)/processor.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/processor.c' object='processor.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 thread_pool.obj `if test -f 'processing/thread_pool.c'; then $(CYGPATH_W) 'processing/thread_pool.c'; else $(CYGPATH_W) '$(srcdir)/processing/thread_pool.c'; fi` +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o processor.obj `if test -f 'processing/processor.c'; then $(CYGPATH_W) 'processing/processor.c'; else $(CYGPATH_W) '$(srcdir)/processing/processor.c'; fi` authenticator.o: sa/authenticators/authenticator.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT authenticator.o -MD -MP -MF "$(DEPDIR)/authenticator.Tpo" -c -o authenticator.o `test -f 'sa/authenticators/authenticator.c' || echo '$(srcdir)/'`sa/authenticators/authenticator.c; \ @@ -1792,6 +1782,20 @@ ike_natd.obj: sa/tasks/ike_natd.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_natd.obj `if test -f 'sa/tasks/ike_natd.c'; then $(CYGPATH_W) 'sa/tasks/ike_natd.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_natd.c'; fi` +ike_mobike.o: sa/tasks/ike_mobike.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_mobike.o -MD -MP -MF "$(DEPDIR)/ike_mobike.Tpo" -c -o ike_mobike.o `test -f 'sa/tasks/ike_mobike.c' || echo '$(srcdir)/'`sa/tasks/ike_mobike.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_mobike.Tpo" "$(DEPDIR)/ike_mobike.Po"; else rm -f "$(DEPDIR)/ike_mobike.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_mobike.c' object='ike_mobike.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_mobike.o `test -f 'sa/tasks/ike_mobike.c' || echo '$(srcdir)/'`sa/tasks/ike_mobike.c + +ike_mobike.obj: sa/tasks/ike_mobike.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_mobike.obj -MD -MP -MF "$(DEPDIR)/ike_mobike.Tpo" -c -o ike_mobike.obj `if test -f 'sa/tasks/ike_mobike.c'; then $(CYGPATH_W) 'sa/tasks/ike_mobike.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_mobike.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_mobike.Tpo" "$(DEPDIR)/ike_mobike.Po"; else rm -f "$(DEPDIR)/ike_mobike.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_mobike.c' object='ike_mobike.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_mobike.obj `if test -f 'sa/tasks/ike_mobike.c'; then $(CYGPATH_W) 'sa/tasks/ike_mobike.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_mobike.c'; fi` + ike_rekey.o: sa/tasks/ike_rekey.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_rekey.o -MD -MP -MF "$(DEPDIR)/ike_rekey.Tpo" -c -o ike_rekey.o `test -f 'sa/tasks/ike_rekey.c' || echo '$(srcdir)/'`sa/tasks/ike_rekey.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_rekey.Tpo" "$(DEPDIR)/ike_rekey.Po"; else rm -f "$(DEPDIR)/ike_rekey.Tpo"; exit 1; fi @@ -1806,6 +1810,20 @@ ike_rekey.obj: sa/tasks/ike_rekey.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_rekey.obj `if test -f 'sa/tasks/ike_rekey.c'; then $(CYGPATH_W) 'sa/tasks/ike_rekey.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_rekey.c'; fi` +ike_reauth.o: sa/tasks/ike_reauth.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_reauth.o -MD -MP -MF "$(DEPDIR)/ike_reauth.Tpo" -c -o ike_reauth.o `test -f 'sa/tasks/ike_reauth.c' || echo '$(srcdir)/'`sa/tasks/ike_reauth.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_reauth.Tpo" "$(DEPDIR)/ike_reauth.Po"; else rm -f "$(DEPDIR)/ike_reauth.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_reauth.c' object='ike_reauth.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_reauth.o `test -f 'sa/tasks/ike_reauth.c' || echo '$(srcdir)/'`sa/tasks/ike_reauth.c + +ike_reauth.obj: sa/tasks/ike_reauth.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_reauth.obj -MD -MP -MF "$(DEPDIR)/ike_reauth.Tpo" -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`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_reauth.Tpo" "$(DEPDIR)/ike_reauth.Po"; else rm -f "$(DEPDIR)/ike_reauth.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_reauth.c' object='ike_reauth.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_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` + task.o: sa/tasks/task.c @am__fastdepCC_TRUE@ if $(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@ then mv -f "$(DEPDIR)/task.Tpo" "$(DEPDIR)/task.Po"; else rm -f "$(DEPDIR)/task.Tpo"; exit 1; fi diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c index 5f46cd29e..5fda36925 100644 --- a/src/charon/bus/bus.c +++ b/src/charon/bus/bus.c @@ -238,30 +238,13 @@ static active_listener_t *get_active_listener(private_bus_t *this) return found; } -typedef struct cancel_info_t cancel_info_t; - -/** - * cancellation info to cancel a listening operation cleanly - */ -struct cancel_info_t { - /** - * mutex to unlock on cancellation - */ - pthread_mutex_t *mutex; - - /** - * listener to unregister - */ - active_listener_t *listener; -}; - /** * disable a listener to cleanly clean up */ -static void unregister(cancel_info_t *info) +static void unregister(active_listener_t *listener) { - info->listener->state = UNREGISTERED; - pthread_mutex_unlock(info->mutex); + listener->state = UNREGISTERED; + pthread_cond_broadcast(&listener->cond); } /** @@ -272,7 +255,6 @@ static signal_t listen_(private_bus_t *this, level_t *level, int *thread, { active_listener_t *listener; int oldstate; - cancel_info_t info; pthread_mutex_lock(&this->mutex); listener = get_active_listener(this); @@ -281,13 +263,13 @@ static signal_t listen_(private_bus_t *this, level_t *level, int *thread, 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. */ - info.mutex = &this->mutex; - info.listener = listener; - pthread_cleanup_push((void*)unregister, &info); + 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); @@ -320,7 +302,7 @@ static void set_listen_state(private_bus_t *this, bool active) { listener->state = UNREGISTERED; /* say hello to signal emitter; we are finished processing the signal */ - pthread_cond_signal(&listener->cond); + pthread_cond_broadcast(&listener->cond); } pthread_mutex_unlock(&this->mutex); @@ -390,7 +372,7 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level, active_listener->format = format; va_copy(active_listener->args, args); active_listener->state = REGISTERED; - pthread_cond_signal(&active_listener->cond); + pthread_cond_broadcast(&active_listener->cond); } } diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h index 4b46c7e82..e54fb1b1b 100644 --- a/src/charon/bus/bus.h +++ b/src/charon/bus/bus.h @@ -39,14 +39,18 @@ typedef struct bus_t bus_t; * * Signaling is for different purporses. First, it allows debugging via * "debugging signal messages", sencondly, it allows to follow certain - * mechanisms currently going on in the daemon. As we are multithreaded, - * and of multiple transactions are involved, it's not possible to follow + * mechanisms currently going on in the daemon. As we are multithreaded, + * and multiple transactions are involved, it's not possible to follow * one connection setup without further infrastructure. These infrastructure * is provided by the bus and the signals the daemon emits to the bus. * * There are different scenarios to follow these signals, but all have * the same scheme. First, a START signal is emitted to indicate the daemon - * has started to + * has started to do something. After a start signal, a SUCCESS or a FAILED + * signal of the same type follows. This allows to track the operation. Any + * Debug signal betwee a START and a SUCCESS/FAILED belongs to that operation + * if the IKE_SA is the same. The thread may change, as multiple threads + * may be involved in a complex scenario. * * @ingroup bus */ @@ -247,7 +251,9 @@ 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. + * 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. * * @ingroup bus */ @@ -283,7 +289,7 @@ struct bus_t { * 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 might + * The listen() function is (has) a thread cancellation point, so you might * want to register cleanup handlers. * * @param this bus diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c index 6964345b3..649fcbcfb 100644 --- a/src/charon/config/credentials/local_credential_store.c +++ b/src/charon/config/credentials/local_credential_store.c @@ -456,7 +456,10 @@ static void add_uris(ca_info_t *issuer, x509_t *cert) while (iterator->iterate(iterator, (void**)&uri)) { - issuer->add_crluri(issuer, uri->get_encoding(uri)); + if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) + { + issuer->add_crluri(issuer, uri->get_encoding(uri)); + } } iterator->destroy(iterator); @@ -465,7 +468,10 @@ static void add_uris(ca_info_t *issuer, x509_t *cert) while (iterator->iterate(iterator, (void**)&uri)) { - issuer->add_ocspuri(issuer, uri->get_encoding(uri)); + if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) + { + issuer->add_ocspuri(issuer, uri->get_encoding(uri)); + } } iterator->destroy(iterator); } diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c index b399074d1..da39c434d 100644 --- a/src/charon/config/traffic_selector.c +++ b/src/charon/config/traffic_selector.c @@ -175,6 +175,7 @@ static int print(FILE *stream, const struct printf_info *info, bool has_proto; bool has_ports; size_t written = 0; + u_int32_t from[4], to[4]; if (this == NULL) { @@ -193,7 +194,11 @@ static int print(FILE *stream, const struct printf_info *info, return written; } - if (this->dynamic) + memset(from, 0, sizeof(from)); + memset(to, 0xFF, sizeof(to)); + if (this->dynamic && + memeq(this->from, from, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16) && + memeq(this->to, to, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16)) { return fprintf(stream, "dynamic/%d", this->type == TS_IPV4_ADDR_RANGE ? 32 : 128); @@ -341,6 +346,7 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_ /* we have a match in protocol, port, and address: return it... */ new_ts = traffic_selector_create(protocol, this->type, from_port, to_port); new_ts->type = this->type; + new_ts->dynamic = this->dynamic || other->dynamic; memcpy(new_ts->from, from, size); memcpy(new_ts->to, to, size); @@ -475,11 +481,6 @@ static u_int8_t get_protocol(private_traffic_selector_t *this) */ static bool is_host(private_traffic_selector_t *this, host_t *host) { - if (this->dynamic) - { - return TRUE; - } - if (host) { chunk_t addr; @@ -498,7 +499,12 @@ static bool is_host(private_traffic_selector_t *this, host_t *host) } else { - size_t length = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16; + size_t length = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16; + + if (this->dynamic) + { + return TRUE; + } if (memeq(this->from, this->to, length)) { diff --git a/src/charon/control/interfaces/dbus_interface.c b/src/charon/control/interfaces/dbus_interface.c index 443df635c..d93a5d048 100644 --- a/src/charon/control/interfaces/dbus_interface.c +++ b/src/charon/control/interfaces/dbus_interface.c @@ -30,6 +30,7 @@ #include <library.h> #include <daemon.h> +#include <processing/jobs/callback_job.h> #define NM_DBUS_SERVICE_STRONG "org.freedesktop.NetworkManager.strongswan" @@ -64,9 +65,9 @@ struct private_dbus_interface_t { NMVPNState state; /** - * dispatcher thread for DBUS messages + * job accepting stroke messages */ - pthread_t thread; + callback_job_t *job; /** * name of the currently active connection @@ -392,14 +393,13 @@ static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg, /** * dispatcher function processed by a seperate thread */ -static void dispatch(private_dbus_interface_t *this) +static job_requeue_t dispatch(private_dbus_interface_t *this) { - charon->drop_capabilities(charon, TRUE); - - while (dbus_connection_read_write_dispatch(this->conn, -1)) + if (dbus_connection_read_write_dispatch(this->conn, -1)) { - /* nothing */ + return JOB_REQUEUE_DIRECT; } + return JOB_REQUEUE_NONE; } /** @@ -407,8 +407,7 @@ static void dispatch(private_dbus_interface_t *this) */ static void destroy(private_dbus_interface_t *this) { - pthread_cancel(this->thread); - pthread_join(this->thread, NULL); + this->job->cancel(this->job); dbus_connection_close(this->conn); dbus_error_free(&this->err); dbus_shutdown(); @@ -469,10 +468,8 @@ interface_t *interface_create() this->state = NM_VPN_STATE_INIT; set_state(this, NM_VPN_STATE_STOPPED); - if (pthread_create(&this->thread, NULL, (void*(*)(void*))dispatch, this) != 0) - { - charon->kill(charon, "unable to create stroke thread"); - } + this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); return &this->public.interface; } diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 6e3427e8e..7885fc2e6 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -43,6 +43,7 @@ #include <control/interface_manager.h> #include <control/interfaces/interface.h> #include <utils/leak_detective.h> +#include <processing/jobs/callback_job.h> #define IKE_PORT 500 #define PATH_BUF 256 @@ -69,9 +70,9 @@ struct private_stroke_interface_t { int socket; /** - * Thread which reads from the Socket + * job accepting stroke messages */ - pthread_t threads[STROKE_THREADS]; + callback_job_t *job; }; typedef struct stroke_log_info_t stroke_log_info_t; @@ -224,8 +225,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) /** * Add a connection to the configuration list */ -static void stroke_add_conn(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_add_conn(stroke_msg_t *msg, FILE *out) { ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; @@ -288,16 +288,18 @@ static void stroke_add_conn(private_stroke_interface_t *this, msg->add_conn.other = tmp_end; free(interface); } - if (!interface) + else { interface = charon->kernel_interface->get_interface( charon->kernel_interface, my_host); if (!interface) { - DBG1(DBG_CFG, "left nor right host is our side, aborting\n"); - goto destroy_hosts; + DBG1(DBG_CFG, "left nor right host is our side, assuming left=local"); + } + else + { + free(interface); } - free(interface); } my_id = identification_create_from_string(msg->add_conn.me.id ? @@ -628,8 +630,7 @@ destroy_hosts: /** * Delete a connection from the list */ -static void stroke_del_conn(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_del_conn(stroke_msg_t *msg, FILE *out) { iterator_t *peer_iter, *child_iter; peer_cfg_t *peer, *child; @@ -747,8 +748,7 @@ static peer_cfg_t *get_peer_cfg_by_name(char *name) /** * initiate a connection by name */ -static void stroke_initiate(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_initiate(stroke_msg_t *msg, FILE *out) { peer_cfg_t *peer_cfg; child_cfg_t *child_cfg; @@ -781,7 +781,6 @@ static void stroke_initiate(private_stroke_interface_t *this, info.out = out; info.level = msg->output_verbosity; - charon->interfaces->initiate(charon->interfaces, peer_cfg, child_cfg, (interface_manager_cb_t)stroke_log, &info); } @@ -789,8 +788,7 @@ static void stroke_initiate(private_stroke_interface_t *this, /** * route a policy (install SPD entries) */ -static void stroke_route(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_route(stroke_msg_t *msg, FILE *out) { peer_cfg_t *peer_cfg; child_cfg_t *child_cfg; @@ -830,8 +828,7 @@ static void stroke_route(private_stroke_interface_t *this, /** * unroute a policy */ -static void stroke_unroute(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_unroute(stroke_msg_t *msg, FILE *out) { char *name; ike_sa_t *ike_sa; @@ -874,8 +871,7 @@ static void stroke_unroute(private_stroke_interface_t *this, /** * terminate a connection by name */ -static void stroke_terminate(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_terminate(stroke_msg_t *msg, FILE *out) { char *string, *pos = NULL, *name = NULL; u_int32_t id = 0; @@ -979,8 +975,7 @@ static void stroke_terminate(private_stroke_interface_t *this, /** * Add a ca information record to the cainfo list */ -static void stroke_add_ca(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_add_ca(stroke_msg_t *msg, FILE *out) { x509_t *cacert; ca_info_t *ca_info; @@ -1047,8 +1042,7 @@ static void stroke_add_ca(private_stroke_interface_t *this, /** * Delete a ca information record from the cainfo list */ -static void stroke_del_ca(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_del_ca(stroke_msg_t *msg, FILE *out) { status_t status; @@ -1194,11 +1188,9 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) /** * show status of daemon */ -static void stroke_status(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out, bool all) +static void stroke_status(stroke_msg_t *msg, FILE *out, bool all) { iterator_t *iterator, *children; - linked_list_t *list; host_t *host; peer_cfg_t *peer_cfg; ike_cfg_t *ike_cfg; @@ -1218,21 +1210,20 @@ static void stroke_status(private_stroke_interface_t *this, fprintf(out, "Performance:\n"); fprintf(out, " worker threads: %d idle of %d,", - charon->thread_pool->get_idle_threads(charon->thread_pool), - charon->thread_pool->get_pool_size(charon->thread_pool)); + charon->processor->get_idle_threads(charon->processor), + charon->processor->get_total_threads(charon->processor)); fprintf(out, " job queue load: %d,", - charon->job_queue->get_count(charon->job_queue)); + charon->processor->get_job_load(charon->processor)); fprintf(out, " scheduled events: %d\n", - charon->event_queue->get_count(charon->event_queue)); - list = charon->kernel_interface->create_address_list(charon->kernel_interface); - - fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list)); - while (list->remove_first(list, (void**)&host) == SUCCESS) + charon->scheduler->get_job_load(charon->scheduler)); + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + fprintf(out, "Listening IP addresses:\n"); + while (iterator->iterate(iterator, (void**)&host)) { fprintf(out, " %H\n", host); - host->destroy(host); } - list->destroy(list); + iterator->destroy(iterator); fprintf(out, "Connections:\n"); iterator = charon->backends->create_iterator(charon->backends); @@ -1312,8 +1303,8 @@ static void stroke_status(private_stroke_interface_t *this, /** * list all authority certificates matching a specified flag */ -static void list_auth_certificates(private_stroke_interface_t *this, u_int flag, - const char *label, bool utc, FILE *out) +static void list_auth_certificates(u_int flag, const char *label, + bool utc, FILE *out) { bool first = TRUE; x509_t *cert; @@ -1341,8 +1332,7 @@ static void list_auth_certificates(private_stroke_interface_t *this, u_int flag /** * list various information */ -static void stroke_list(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_list(stroke_msg_t *msg, FILE *out) { iterator_t *iterator; @@ -1372,15 +1362,15 @@ static void stroke_list(private_stroke_interface_t *this, } if (msg->list.flags & LIST_CACERTS) { - list_auth_certificates(this, AUTH_CA, "CA", msg->list.utc, out); + list_auth_certificates(AUTH_CA, "CA", msg->list.utc, out); } if (msg->list.flags & LIST_OCSPCERTS) { - list_auth_certificates(this, AUTH_OCSP, "OCSP", msg->list.utc, out); + list_auth_certificates(AUTH_OCSP, "OCSP", msg->list.utc, out); } if (msg->list.flags & LIST_AACERTS) { - list_auth_certificates(this, AUTH_AA, "AA", msg->list.utc, out); + list_auth_certificates(AUTH_AA, "AA", msg->list.utc, out); } if (msg->list.flags & LIST_CAINFOS) { @@ -1453,8 +1443,7 @@ static void stroke_list(private_stroke_interface_t *this, /** * reread various information */ -static void stroke_reread(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_reread(stroke_msg_t *msg, FILE *out) { if (msg->reread.flags & REREAD_CACERTS) { @@ -1473,8 +1462,7 @@ static void stroke_reread(private_stroke_interface_t *this, /** * purge various information */ -static void stroke_purge(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_purge(stroke_msg_t *msg, FILE *out) { if (msg->purge.flags & PURGE_OCSP) { @@ -1510,8 +1498,7 @@ signal_t get_signal_from_logtype(char *type) /** * set the verbosity debug output */ -static void stroke_loglevel(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out) +static void stroke_loglevel(stroke_msg_t *msg, FILE *out) { signal_t signal; @@ -1533,20 +1520,22 @@ static void stroke_loglevel(private_stroke_interface_t *this, /** * process a stroke request from the socket pointed by "fd" */ -static void stroke_process(private_stroke_interface_t *this, int strokefd) +static job_requeue_t stroke_process(int *fdp) { stroke_msg_t *msg; u_int16_t msg_length; ssize_t bytes_read; FILE *out; + int strokefd = *fdp; /* peek the length */ bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK); if (bytes_read != sizeof(msg_length)) { - DBG1(DBG_CFG, "reading length of stroke message failed"); + DBG1(DBG_CFG, "reading length of stroke message failed: %s", + strerror(errno)); close(strokefd); - return; + return JOB_REQUEUE_NONE; } /* read message */ @@ -1556,105 +1545,107 @@ static void stroke_process(private_stroke_interface_t *this, int strokefd) { DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno)); close(strokefd); - return; + return JOB_REQUEUE_NONE; } - out = fdopen(dup(strokefd), "w"); + out = fdopen(strokefd, "w"); if (out == NULL) { DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno)); close(strokefd); free(msg); - return; + return JOB_REQUEUE_NONE; } DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length); + /* the stroke_* functions are blocking, as they listen on the bus. Add + * cancellation handlers. */ + pthread_cleanup_push((void*)fclose, out); + pthread_cleanup_push(free, msg); + switch (msg->type) { case STR_INITIATE: - stroke_initiate(this, msg, out); + stroke_initiate(msg, out); break; case STR_ROUTE: - stroke_route(this, msg, out); + stroke_route(msg, out); break; case STR_UNROUTE: - stroke_unroute(this, msg, out); + stroke_unroute(msg, out); break; case STR_TERMINATE: - stroke_terminate(this, msg, out); + stroke_terminate(msg, out); break; case STR_STATUS: - stroke_status(this, msg, out, FALSE); + stroke_status(msg, out, FALSE); break; case STR_STATUS_ALL: - stroke_status(this, msg, out, TRUE); + stroke_status(msg, out, TRUE); break; case STR_ADD_CONN: - stroke_add_conn(this, msg, out); + stroke_add_conn(msg, out); break; case STR_DEL_CONN: - stroke_del_conn(this, msg, out); + stroke_del_conn(msg, out); break; case STR_ADD_CA: - stroke_add_ca(this, msg, out); + stroke_add_ca(msg, out); break; case STR_DEL_CA: - stroke_del_ca(this, msg, out); + stroke_del_ca(msg, out); break; case STR_LOGLEVEL: - stroke_loglevel(this, msg, out); + stroke_loglevel(msg, out); break; case STR_LIST: - stroke_list(this, msg, out); + stroke_list(msg, out); break; case STR_REREAD: - stroke_reread(this, msg, out); + stroke_reread(msg, out); break; case STR_PURGE: - stroke_purge(this, msg, out); + stroke_purge(msg, out); break; default: DBG1(DBG_CFG, "received unknown stroke"); } - fclose(out); - close(strokefd); - free(msg); + /* remove and execute cancellation handlers */ + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + + return JOB_REQUEUE_NONE; } + /** * Implementation of private_stroke_interface_t.stroke_receive. */ -static void stroke_receive(private_stroke_interface_t *this) +static job_requeue_t stroke_receive(private_stroke_interface_t *this) { struct sockaddr_un strokeaddr; int strokeaddrlen = sizeof(strokeaddr); + int strokefd, *fdp; int oldstate; - int strokefd; - - charon->drop_capabilities(charon, TRUE); + callback_job_t *job; - /* ignore sigpipe. writing over the pipe back to the console - * only fails if SIGPIPE is ignored. */ - signal(SIGPIPE, SIG_IGN); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); + pthread_setcancelstate(oldstate, NULL); - /* disable cancellation by default */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - - while (TRUE) + if (strokefd < 0) { - /* wait for connections, but allow thread to terminate */ - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); - pthread_setcancelstate(oldstate, NULL); - - if (strokefd < 0) - { - DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno)); - continue; - } - stroke_process(this, strokefd); + DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno)); + return JOB_REQUEUE_FAIR; } + + fdp = malloc_thing(int); + *fdp = strokefd; + job = callback_job_create((callback_job_cb_t)stroke_process, fdp, free, this->job); + charon->processor->queue_job(charon->processor, (job_t*)job); + + return JOB_REQUEUE_FAIR; } /** @@ -1662,17 +1653,9 @@ static void stroke_receive(private_stroke_interface_t *this) */ static void destroy(private_stroke_interface_t *this) { - int i; - - for (i = 0; i < STROKE_THREADS; i++) - { - pthread_cancel(this->threads[i]); - pthread_join(this->threads[i], NULL); - } - - close(this->socket); - unlink(socket_addr.sun_path); + this->job->cancel(this->job); free(this); + unlink(socket_addr.sun_path); } /* @@ -1682,7 +1665,6 @@ interface_t *interface_create() { private_stroke_interface_t *this = malloc_thing(private_stroke_interface_t); mode_t old; - int i; /* public functions */ this->public.interface.destroy = (void (*)(interface_t*))destroy; @@ -1715,14 +1697,10 @@ interface_t *interface_create() return NULL; } - /* start threads reading from the socket */ - for (i = 0; i < STROKE_THREADS; i++) - { - if (pthread_create(&this->threads[i], NULL, (void*(*)(void*))stroke_receive, this) != 0) - { - charon->kill(charon, "unable to create stroke thread"); - } - } + this->job = callback_job_create((callback_job_cb_t)stroke_receive, + this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); return &this->public.interface; } + diff --git a/src/charon/control/interfaces/xml_interface.c b/src/charon/control/interfaces/xml_interface.c index e570f2543..992377436 100644 --- a/src/charon/control/interfaces/xml_interface.c +++ b/src/charon/control/interfaces/xml_interface.c @@ -24,8 +24,22 @@ #include "xml_interface.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <libxml/xmlreader.h> +#include <libxml/xmlwriter.h> + #include <library.h> #include <daemon.h> +#include <processing/jobs/callback_job.h> + +static struct sockaddr_un socket_addr = { AF_UNIX, "/var/run/charon.xml"}; typedef struct private_xml_interface_t private_xml_interface_t; @@ -39,14 +53,166 @@ struct private_xml_interface_t { * Public part of xml_t object. */ xml_interface_t public; + + /** + * XML unix socket fd + */ + int socket; + + /** + * job accepting stroke messages + */ + callback_job_t *job; }; +/** + * process a getRequest message + */ +static void process_get(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + if (/* <GetResponse> */ + xmlTextWriterStartElement(writer, "GetResponse") < 0 || + /* <Status Code="200"><Message/></Status> */ + xmlTextWriterStartElement(writer, "Status") < 0 || + xmlTextWriterWriteAttribute(writer, "Code", "200") < 0 || + xmlTextWriterStartElement(writer, "Message") < 0 || + xmlTextWriterEndElement(writer) < 0 || + xmlTextWriterEndElement(writer) < 0 || + /* <ConnectionList/> */ + xmlTextWriterStartElement(writer, "ConnectionList") < 0 || + xmlTextWriterEndElement(writer) < 0 || + /* </GetResponse> */ + xmlTextWriterEndElement(writer) < 0) + { + DBG1(DBG_CFG, "error writing XML document (GetResponse)"); + } +} + +/** + * read from a opened connection and process it + */ +static job_requeue_t process(int *fdp) +{ + int oldstate, fd = *fdp; + char buffer[4096]; + size_t len; + xmlTextReaderPtr reader; + xmlTextWriterPtr writer; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + len = read(fd, buffer, sizeof(buffer)); + pthread_setcancelstate(oldstate, NULL); + if (len <= 0) + { + close(fd); + DBG2(DBG_CFG, "SMP XML connection closed"); + return JOB_REQUEUE_NONE; + } + + reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0); + if (reader == NULL) + { + DBG1(DBG_CFG, "opening SMP XML reader failed"); + return JOB_REQUEUE_FAIR;; + } + + writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL)); + if (writer == NULL) + { + xmlFreeTextReader(reader); + DBG1(DBG_CFG, "opening SMP XML writer failed"); + return JOB_REQUEUE_FAIR;; + } + + /* create the standard message parts */ + if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) < 0 || + /* <SMPMessage xmlns="http://www.strongswan.org/smp/1.0"> */ + xmlTextWriterStartElement(writer, "SMPMessage") < 0 || + xmlTextWriterWriteAttribute(writer, "xmlns", + "http://www.strongswan.org/smp/1.0") < 0 || + /* <Body> */ + xmlTextWriterStartElement(writer, "Body") < 0) + { + xmlFreeTextReader(reader); + xmlFreeTextWriter(writer); + DBG1(DBG_CFG, "creating SMP XML message failed"); + return JOB_REQUEUE_FAIR;; + } + + while (TRUE) + { + switch (xmlTextReaderRead(reader)) + { + case 1: + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "GetRequest")) + { + process_get(reader, writer); + break; + } + } + continue; + } + case 0: + /* end of XML */ + break; + default: + DBG1(DBG_CFG, "parsing SMP XML message failed"); + break; + } + xmlFreeTextReader(reader); + break; + } + /* write </Body></SMPMessage> and close document */ + if (xmlTextWriterEndDocument(writer) < 0) + { + DBG1(DBG_CFG, "completing SMP XML message failed"); + } + xmlFreeTextWriter(writer); + + /* write a newline to indicate end of xml */ + write(fd, "\n", 1); + return JOB_REQUEUE_FAIR;; +} + +/** + * accept from XML socket and create jobs to process connections + */ +static job_requeue_t dispatch(private_xml_interface_t *this) +{ + struct sockaddr_un strokeaddr; + int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr); + callback_job_t *job; + + /* wait for connections, but allow thread to terminate */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); + pthread_setcancelstate(oldstate, NULL); + + if (fd < 0) + { + DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno)); + sleep(1); + return JOB_REQUEUE_FAIR;; + } + + fdp = malloc_thing(int); + *fdp = fd; + job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job); + charon->processor->queue_job(charon->processor, (job_t*)job); + + return JOB_REQUEUE_DIRECT; +} /** * Implementation of itnerface_t.destroy. */ static void destroy(private_xml_interface_t *this) { + this->job->cancel(this->job); + unlink(socket_addr.sun_path); free(this); } @@ -56,8 +222,40 @@ static void destroy(private_xml_interface_t *this) interface_t *interface_create() { private_xml_interface_t *this = malloc_thing(private_xml_interface_t); + mode_t old; - this->public.interface.destroy = (void (*)(xml_interface_t*))destroy; + this->public.interface.destroy = (void (*)(interface_t*))destroy; + + /* set up unix socket */ + this->socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (this->socket == -1) + { + DBG1(DBG_CFG, "could not create XML socket"); + free(this); + return NULL; + } + + old = umask(~S_IRWXU); + if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0) + { + DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno)); + close(this->socket); + free(this); + return NULL; + } + umask(old); + + if (listen(this->socket, 0) < 0) + { + DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno)); + close(this->socket); + free(this); + return NULL; + } + + this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); return &this->public.interface; } + diff --git a/src/charon/daemon.c b/src/charon/daemon.c index 62e29b365..37699f83f 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -115,25 +115,26 @@ static void dbg_stderr(int level, char *fmt, ...) */ static void run(private_daemon_t *this) { - /* reselect signals for this thread */ - sigemptyset(&(this->signal_set)); - sigaddset(&(this->signal_set), SIGINT); - sigaddset(&(this->signal_set), SIGHUP); - sigaddset(&(this->signal_set), SIGTERM); - pthread_sigmask(SIG_BLOCK, &(this->signal_set), 0); - - while(TRUE) + sigset_t set; + + /* handle SIGINT, SIGHUP ans SIGTERM in this handler */ + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGTERM); + + while (TRUE) { - int signal_number; + int sig; int error; - error = sigwait(&(this->signal_set), &signal_number); - if(error) + error = sigwait(&set, &sig); + if (error) { DBG1(DBG_DMN, "error %d while waiting for a signal", error); return; } - switch (signal_number) + switch (sig) { case SIGHUP: { @@ -146,11 +147,13 @@ static void run(private_daemon_t *this) return; } case SIGTERM: + { DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down"); return; + } default: { - DBG1(DBG_DMN, "unknown signal %d received. Ignored", signal_number); + DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig); break; } } @@ -162,33 +165,22 @@ static void run(private_daemon_t *this) */ static void destroy(private_daemon_t *this) { - /* destruction is a non trivial task, we need to follow - * a strict order to prevent threading issues! - * Kill active threads first, except the sender, as - * the killed IKE_SA want to send delete messages. - */ - /* we don't want to receive anything anymore... */ - DESTROY_IF(this->public.receiver); - /* ignore all incoming user requests */ - DESTROY_IF(this->public.interfaces); - /* stop scheduing jobs */ - DESTROY_IF(this->public.scheduler); - /* stop processing jobs */ - DESTROY_IF(this->public.thread_pool); - /* shut down manager with all IKE SAs */ + /* terminate all idle threads */ + this->public.processor->set_threads(this->public.processor, 0); + /* close all IKE_SAs */ DESTROY_IF(this->public.ike_sa_manager); - /* all child SAs should be down now, so kill kernel interface */ - DESTROY_IF(this->public.kernel_interface); - /* destroy other infrastructure */ - DESTROY_IF(this->public.job_queue); - DESTROY_IF(this->public.event_queue); - DESTROY_IF(this->public.credentials); + DESTROY_IF(this->public.scheduler); + DESTROY_IF(this->public.interfaces); DESTROY_IF(this->public.backends); - /* we hope the sender could send the outstanding deletes, but - * we shut down here at any cost */ + DESTROY_IF(this->public.credentials); + DESTROY_IF(this->public.kernel_interface); DESTROY_IF(this->public.sender); + DESTROY_IF(this->public.receiver); DESTROY_IF(this->public.socket); - /* before destroying bus with its listeners, rehook library logs */ + /* wait until all threads are gone */ + DESTROY_IF(this->public.processor); + + /* rehook library logging, shutdown logging */ dbg = dbg_stderr; DESTROY_IF(this->public.bus); DESTROY_IF(this->public.outlog); @@ -197,7 +189,6 @@ static void destroy(private_daemon_t *this) free(this); } - /** * Enforce daemon shutdown, with a given reason to do so. */ @@ -228,6 +219,7 @@ static void drop_capabilities(private_daemon_t *this, bool full) { struct __user_cap_header_struct hdr; struct __user_cap_data_struct data; + /* CAP_NET_ADMIN is needed to use netlink */ u_int32_t keep = (1<<CAP_NET_ADMIN); @@ -242,11 +234,11 @@ static void drop_capabilities(private_daemon_t *this, bool full) } else { - /* CAP_NET_BIND_SERVICE to bind services below port 1024, - * CAP_NET_RAW to create RAW sockets. - * CAP_DAC_READ_SEARCH is needed to read ipsec.secrets */ + /* CAP_NET_BIND_SERVICE to bind services below port 1024 */ keep |= (1<<CAP_NET_BIND_SERVICE); + /* CAP_NET_RAW to create RAW sockets */ keep |= (1<<CAP_NET_RAW); + /* CAP_DAC_READ_SEARCH to read ipsec.secrets */ keep |= (1<<CAP_DAC_READ_SEARCH); } @@ -257,7 +249,7 @@ static void drop_capabilities(private_daemon_t *this, bool full) if (capset(&hdr, &data)) { - kill_daemon(this, "unable to drop threads capabilities"); + kill_daemon(this, "unable to drop daemon capabilities"); } } @@ -266,7 +258,6 @@ static void drop_capabilities(private_daemon_t *this, bool full) */ static void initialize(private_daemon_t *this, bool syslog, level_t levels[]) { - credential_store_t* credentials; signal_t signal; /* for uncritical pseudo random numbers */ @@ -298,38 +289,32 @@ static void initialize(private_daemon_t *this, bool syslog, level_t levels[]) DBG1(DBG_DMN, "starting charon (strongSwan Version %s)", VERSION); - this->public.socket = socket_create(IKEV2_UDP_PORT, IKEV2_NATT_PORT); this->public.ike_sa_manager = ike_sa_manager_create(); - this->public.job_queue = job_queue_create(); - this->public.event_queue = event_queue_create(); - this->public.credentials = (credential_store_t*)local_credential_store_create(); - this->public.backends = backend_manager_create(); - - /* initialize fetcher_t class */ - fetcher_initialize(); + this->public.processor = processor_create(); + this->public.scheduler = scheduler_create(); /* load secrets, ca certificates and crls */ - credentials = this->public.credentials; - credentials->load_ca_certificates(credentials); - credentials->load_aa_certificates(credentials); - credentials->load_attr_certificates(credentials); - credentials->load_ocsp_certificates(credentials); - credentials->load_crls(credentials); - credentials->load_secrets(credentials); - - /* start building threads, we are multi-threaded NOW */ + this->public.credentials = (credential_store_t*)local_credential_store_create(); + this->public.credentials->load_ca_certificates(this->public.credentials); + this->public.credentials->load_aa_certificates(this->public.credentials); + this->public.credentials->load_attr_certificates(this->public.credentials); + this->public.credentials->load_ocsp_certificates(this->public.credentials); + this->public.credentials->load_crls(this->public.credentials); + this->public.credentials->load_secrets(this->public.credentials); + 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.sender = sender_create(); this->public.receiver = receiver_create(); - this->public.scheduler = scheduler_create(); - this->public.kernel_interface = kernel_interface_create(); - this->public.thread_pool = thread_pool_create(NUMBER_OF_WORKING_THREADS); + } /** * Handle SIGSEGV/SIGILL signals raised by threads */ -void signal_handler(int signal) +static void segv_handler(int signal) { #ifdef HAVE_BACKTRACE void *array[20]; @@ -340,7 +325,7 @@ void signal_handler(int signal) size = backtrace(array, 20); strings = backtrace_symbols(array, size); - DBG1(DBG_DMN, "thread %u received %s. Dumping %d frames from stack:", + DBG1(DBG_JOB, "thread %u received %s. Dumping %d frames from stack:", pthread_self(), signal == SIGSEGV ? "SIGSEGV" : "SIGILL", size); for (i = 0; i < size; i++) @@ -352,7 +337,7 @@ void signal_handler(int signal) DBG1(DBG_DMN, "thread %u received %s", pthread_self(), signal == SIGSEGV ? "SIGSEGV" : "SIGILL"); #endif /* HAVE_BACKTRACE */ - DBG1(DBG_DMN, "killing ourself hard after SIGSEGV"); + DBG1(DBG_DMN, "killing ourself, received critical signal"); raise(SIGKILL); } @@ -361,25 +346,22 @@ void signal_handler(int signal) */ private_daemon_t *daemon_create(void) { - private_daemon_t *this = malloc_thing(private_daemon_t); struct sigaction action; + private_daemon_t *this = malloc_thing(private_daemon_t); /* assign methods */ this->public.kill = (void (*) (daemon_t*,char*))kill_daemon; - this->public.drop_capabilities = (void(*)(daemon_t*,bool))drop_capabilities; /* NULL members for clean destruction */ this->public.socket = NULL; this->public.ike_sa_manager = NULL; - this->public.job_queue = NULL; - this->public.event_queue = NULL; this->public.credentials = NULL; this->public.backends = NULL; this->public.sender= NULL; this->public.receiver = NULL; this->public.scheduler = NULL; this->public.kernel_interface = NULL; - this->public.thread_pool = NULL; + this->public.processor = NULL; this->public.interfaces = NULL; this->public.bus = NULL; this->public.outlog = NULL; @@ -388,20 +370,22 @@ private_daemon_t *daemon_create(void) this->main_thread_id = pthread_self(); - /* setup signal handling for all threads */ - sigemptyset(&(this->signal_set)); - sigaddset(&(this->signal_set), SIGSEGV); - sigaddset(&(this->signal_set), SIGINT); - sigaddset(&(this->signal_set), SIGHUP); - sigaddset(&(this->signal_set), SIGTERM); - pthread_sigmask(SIG_BLOCK, &(this->signal_set), 0); - - /* setup SIGSEGV handler for all threads */ - action.sa_handler = signal_handler; - action.sa_mask = this->signal_set; + /* add handler for SEGV and ILL, + * add handler for USR1 (cancellation). + * INT, TERM and HUP are handled by sigwait() in run() */ + action.sa_handler = segv_handler; action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGINT); + sigaddset(&action.sa_mask, SIGTERM); + sigaddset(&action.sa_mask, SIGHUP); sigaction(SIGSEGV, &action, NULL); sigaction(SIGILL, &action, NULL); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + + pthread_sigmask(SIG_SETMASK, &action.sa_mask, 0); + return this; } @@ -445,15 +429,15 @@ int main(int argc, char *argv[]) private_daemon_t *private_charon; FILE *pid_file; struct stat stb; - linked_list_t *list; - host_t *host; level_t levels[DBG_MAX]; int signal; - prctl(PR_SET_KEEPCAPS, 1); + private_charon = daemon_create(); + charon = (daemon_t*)private_charon; - /* drop the capabilities we won't need at all */ - drop_capabilities(NULL, FALSE); + /* drop the capabilities we won't need for initialization */ + prctl(PR_SET_KEEPCAPS, 1); + drop_capabilities(private_charon, FALSE); /* use CTRL loglevel for default */ for (signal = 0; signal < DBG_MAX; signal++) @@ -522,13 +506,11 @@ int main(int argc, char *argv[]) } break; } - - private_charon = daemon_create(); - charon = (daemon_t*)private_charon; /* initialize daemon */ initialize(private_charon, use_syslog, levels); - + /* initialize fetcher_t class */ + fetcher_initialize(); /* load pluggable EAP modules */ eap_method_load(eapdir); @@ -549,19 +531,12 @@ int main(int argc, char *argv[]) fclose(pid_file); } - /* log socket info */ - list = charon->kernel_interface->create_address_list(charon->kernel_interface); - DBG1(DBG_NET, "listening on %d addresses:", list->get_count(list)); - while (list->remove_first(list, (void**)&host) == SUCCESS) - { - DBG1(DBG_NET, " %H", host); - host->destroy(host); - } - list->destroy(list); - /* drop additional capabilites (bind & root) */ drop_capabilities(private_charon, TRUE); + /* start the engine, go multithreaded */ + charon->processor->set_threads(charon->processor, WORKER_THREADS); + /* run daemon */ run(private_charon); diff --git a/src/charon/daemon.h b/src/charon/daemon.h index 640bc6a09..0b5205ce7 100644 --- a/src/charon/daemon.h +++ b/src/charon/daemon.h @@ -33,9 +33,7 @@ typedef struct daemon_t daemon_t; #include <network/receiver.h> #include <network/socket.h> #include <processing/scheduler.h> -#include <processing/thread_pool.h> -#include <processing/job_queue.h> -#include <processing/event_queue.h> +#include <processing/processor.h> #include <kernel/kernel_interface.h> #include <control/interface_manager.h> #include <bus/bus.h> @@ -49,50 +47,73 @@ typedef struct daemon_t daemon_t; * * @brief IKEv2 keying daemon. * - * @section Architecture - * * All IKEv2 stuff is handled in charon. It uses a newer and more flexible - * architecture than pluto. Charon uses a thread-pool, which allows parallel - * execution SA-management. Beside the thread-pool, there are some special purpose - * threads which do their job for the common health of the daemon. - @verbatim - +------+ - | E Q | - | v u |---+ +------+ +------+ - | e e | | | | | IKE- | - | n u | +-----------+ | |--| SA | - | t e | | | | I M | +------+ - +------------+ | - | | Scheduler | | K a | - | receiver | +------+ | | | E n | +------+ - +----+-------+ +-----------+ | - a | | IKE- | - | | +------+ | | S g |--| SA | - +-------+--+ +-----| J Q |---+ +------------+ | A e | +------+ - -| socket | | o u | | | | - r | - +-------+--+ | b e | | Thread- | | | - | | - u | | Pool | | | - +----+-------+ | e |------| |---| | - | sender | +------+ +------------+ +------+ - +------------+ + * architecture than pluto. Charon uses a thread-pool (called processor), + * which allows parallel execution SA-management. All threads originate + * from the processor. Work is delegated to the processor by queueing jobs + * to it. + @verbatim + + +--------+ +-------+ +--------+ +-----------+ +-----------+ + | Stroke | | XML | | DBUS | | Local | | SQLite | + +--------+ +-------+ +--------+ +-----------+ +-----------+ + | | | | | + +---------------------------------+ +----------------------------+ + | Interfaces | | Backends | + +---------------------------------+ +----------------------------+ + + + +------------+ +-----------+ +------+ +----------+ + | receiver | | | | | +------+ | CHILD_SA | + +----+-------+ | Scheduler | | IKE- | | IKE- |--+----------+ + | | | | SA |--| SA | | CHILD_SA | + +-------+--+ +-----------+ | | +------+ +----------+ + <->| socket | | | Man- | + +-------+--+ +-----------+ | ager | +------+ +----------+ + | | | | | | IKE- |--| CHILD_SA | + +----+-------+ | Processor |--------| |--| SA | +----------+ + | sender | | | | | +------+ + +------------+ +-----------+ +------+ + + + +---------------------------------+ +----------------------------+ + | Bus | | Kernel Interface | + +---------------------------------+ +----------------------------+ + | | | + +-------------+ +-------------+ V + | File-Logger | | Sys-Logger | ////// + +-------------+ +-------------+ + @endverbatim - * The thread-pool is the heart of the architecture. It processes jobs from a - * (fully synchronized) job-queue. Mostly, a job is associated with a specific - * IKE SA. These IKE SAs are synchronized, only one thread can work one an IKE SA. - * This makes it unnecesary to use further synchronisation methods once a IKE SA - * is checked out. The (rather complex) synchronization of IKE SAs is completely - * done in the IKE SA manager. - * The sceduler is responsible for event firing. It waits until a event in the - * (fully synchronized) event-queue is ready for processing and pushes the event - * down to the job-queue. A thread form the pool will pick it up as quick as - * possible. Every thread can queue events or jobs. Furter, an event can place a - * packet in the sender. The sender thread waits for those packets and sends - * them over the wire, via the socket. The receiver does exactly the opposite of - * the sender. It waits on the socket, reads in packets an places them on the - * job-queue for further processing by a thread from the pool. - * There are even more threads, not drawn in the upper scheme. The stroke thread - * is responsible for reading and processessing commands from another process. The - * kernel interface thread handles communication from and to the kernel via a - * netlink socket. It waits for kernel events and processes them appropriately. + * The scheduler is responsible to execute timed events. Jobs may be queued to + * the scheduler to get executed at a defined time (e.g. rekeying). The scheduler + * does not execute the jobs itself, it queues them to the processor. + * + * The IKE_SA manager managers all IKE_SA. It further handles the synchronization: + * Each IKE_SA must be checked out strictly and checked in again after use. The + * manager guarantees that only one thread may check out a single IKE_SA. This allows + * us to write the (complex) IKE_SAs routines non-threadsave. + * The IKE_SA contain the state and the logic of each IKE_SA and handle the messages. + * + * The CHILD_SA contains state about a IPsec security association and manages them. + * An IKE_SA may have multiple CHILD_SAs. Communication to the kernel takes place + * here through the kernel interface. + * + * The kernel interface installs IPsec security associations, policies routes and + * virtual addresses. It further provides methods to enumerate interfaces and may notify + * the daemon about state changes at lower layers. + * + * The bus receives signals from the different threads and relais them to interested + * listeners. Debugging signals, but also important state changes or error messages are + * sent over the bus. + * It's listeners are not only for logging, but also to track the state of an IKE_SA. + * + * The interface manager loads pluggable controlling interfaces. These are written to control + * the daemon from external inputs (e.g. initiate IKE_SA, close IKE_SA, ...). The interface + * manager further provides a simple API to establish these tasks. + * Backends are pluggable modules which provide configuration. They have to implement an API + * which the daemon core uses to get configuration. */ /** @@ -234,12 +255,9 @@ typedef struct daemon_t daemon_t; /** * @brief Number of threads in the thread pool. * - * There are several other threads, this defines - * only the number of threads in thread_pool_t. - * * @ingroup charon */ -#define NUMBER_OF_WORKING_THREADS 4 +#define WORKER_THREADS 16 /** * UDP Port on which the daemon will listen for incoming traffic. @@ -338,20 +356,11 @@ typedef struct daemon_t daemon_t; * @ingroup charon */ struct daemon_t { + /** * A socket_t instance. */ socket_t *socket; - - /** - * A job_queue_t instance. - */ - job_queue_t *job_queue; - - /** - * A event_queue_t instance. - */ - event_queue_t *event_queue; /** * A ike_sa_manager_t instance. @@ -384,9 +393,9 @@ struct daemon_t { scheduler_t *scheduler; /** - * The Thread pool managing the worker threads. + * Job processing using a thread pool. */ - thread_pool_t *thread_pool; + processor_t *processor; /** * The signaling bus. @@ -419,14 +428,6 @@ struct daemon_t { interface_manager_t *interfaces; /** - * @brief Let the calling thread drop its capabilities. - * - * @param this calling daemon - * @param full TRUE to drop as many as possible - */ - void (*drop_capabilities) (daemon_t *this, bool full); - - /** * @brief Shut down the daemon. * * @param this the daemon to kill diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c index b31b21afa..980ff12b5 100644 --- a/src/charon/encoding/message.c +++ b/src/charon/encoding/message.c @@ -611,9 +611,13 @@ static char* get_string(private_message_t *this, char *buf, int len) int written; char *pos = buf; - written = snprintf(pos, len, "%N %s [", - exchange_type_names, this->exchange_type, - this->is_request ? "request" : "response"); + memset(buf, 0, len); + len--; + + written = snprintf(pos, len, "%N %s %d [", + exchange_type_names, this->exchange_type, + this->is_request ? "request" : "response", + this->message_id); if (written >= len || written < 0) { return ""; @@ -621,16 +625,10 @@ static char* get_string(private_message_t *this, char *buf, int len) pos += written; len -= written; - if (this->payloads->get_count(this->payloads) == 0) - { - snprintf(pos, len, "]"); - return buf; - } - iterator = this->payloads->create_iterator(this->payloads, TRUE); while (iterator->iterate(iterator, (void**)&payload)) { - written = snprintf(pos, len, "%N ", payload_type_short_names, + written = snprintf(pos, len, " %N", payload_type_short_names, payload->get_type(payload)); if (written >= len || written < 0) { @@ -638,13 +636,23 @@ static char* get_string(private_message_t *this, char *buf, int len) } pos += written; len -= written; + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + written = snprintf(pos, len, "(%N)", notify_type_short_names, + notify->get_notify_type(notify)); + if (written >= len || written < 0) + { + return buf; + } + pos += written; + len -= written; + } } iterator->destroy(iterator); /* remove last space */ - pos--; - len++; - snprintf(pos, len, "]"); + snprintf(pos, len, " ]"); return buf; } @@ -734,7 +742,7 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t* iterator_t *iterator; status_t status; chunk_t packet_data; - char str[128]; + char str[256]; if (is_encoded(this)) { @@ -1140,7 +1148,7 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t { status_t status = SUCCESS; payload_type_t current_payload_type; - char str[128]; + char str[256]; current_payload_type = this->first_payload; diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c index a04901a90..e27d3c68f 100644 --- a/src/charon/encoding/payloads/notify_payload.c +++ b/src/charon/encoding/payloads/notify_payload.c @@ -47,14 +47,16 @@ ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL "INVALID_KE_PAYLOAD"); ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, "AUTHENTICATION_FAILED"); -ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, INVALID_SELECTORS, AUTHENTICATION_FAILED, +ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTHENTICATION_FAILED, "SINGLE_PAIR_REQUIRED", "NO_ADDITIONAL_SAS", "INTERNAL_ADDRESS_FAILURE", "FAILED_CP_REQUIRED", "TS_UNACCEPTABLE", - "INVALID_SELECTORS"); -ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, INVALID_SELECTORS, + "INVALID_SELECTORS", + "UNACCEPTABLE_ADDRESSES", + "UNEXPECTED_NAT_DETECTED"); +ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED, "INITIAL_CONTACT", "SET_WINDOW_SIZE", "ADDITIONAL_TS_POSSIBLE", @@ -79,6 +81,59 @@ ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, A "EAP_ONLY_AUTHENTICATION"); ENUM_END(notify_type_names, EAP_ONLY_AUTHENTICATION); + +ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD, + "CRIT"); +ENUM_NEXT(notify_type_short_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD, + "INVAL_IKE_SPI", + "INVAL_MAJOR"); +ENUM_NEXT(notify_type_short_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION, + "INVAL_SYN"); +ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX, + "INVAL_MID"); +ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, + "INVAL_SPI"); +ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, + "NO_PROP"); +ENUM_NEXT(notify_type_short_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, + "INVAL_KE"); +ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, + "AUTH_FAILED"); +ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTHENTICATION_FAILED, + "SINGLE_PAIR", + "NO_ADD_SAS", + "INT_ADDR_FAIL", + "FAIL_CP_REQ", + "TS_UNACCEPT", + "INVAL_SEL", + "UNACCEPT_ADDR", + "UNEXPECT_NAT"); +ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED, + "INIT_CONTACT", + "SET_WINSIZE", + "ADD_TS_POSS", + "IPCOMP_SUPP", + "NATD_S_IP", + "NATD_D_IP", + "COOKIE", + "USE_TRANSP", + "HTTP_CERT_LOOK", + "REKEY_SA", + "ESP_TFC_PAD_N", + "NON_FIRST_FRAG", + "MOBIKE_SUP", + "ADD_4_ADDR", + "ADD_6_ADDR", + "NO_ADD_ADDR", + "UPD_SA_ADDR", + "COOKIE2", + "NO_NATS", + "AUTH_LFT"); +ENUM_NEXT(notify_type_short_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME, + "EAP_ONLY"); +ENUM_END(notify_type_short_names, EAP_ONLY_AUTHENTICATION); + + typedef struct private_notify_payload_t private_notify_payload_t; /** @@ -189,6 +244,8 @@ encoding_rule_t notify_payload_encodings[] = { */ static status_t verify(private_notify_payload_t *this) { + bool bad_length = FALSE; + switch (this->protocol_id) { case PROTO_NONE: @@ -205,30 +262,9 @@ static status_t verify(private_notify_payload_t *this) { case INVALID_KE_PAYLOAD: { - /* check notification data */ - diffie_hellman_group_t dh_group; if (this->notification_data.len != 2) { - DBG1(DBG_ENC, "invalid notify data length for %N (%d)", - notify_type_names, this->notify_type, - this->notification_data.len); - return FAILED; - } - dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr)); - switch (dh_group) - { - case MODP_768_BIT: - case MODP_1024_BIT: - case MODP_1536_BIT: - case MODP_2048_BIT: - case MODP_3072_BIT: - case MODP_4096_BIT: - case MODP_6144_BIT: - case MODP_8192_BIT: - break; - default: - DBG1(DBG_ENC, "Bad DH group (%d)", dh_group); - return FAILED; + bad_length = TRUE; } break; } @@ -237,9 +273,7 @@ static status_t verify(private_notify_payload_t *this) { if (this->notification_data.len != HASH_SIZE_SHA1) { - DBG1(DBG_ENC, "invalid %N notify length", - notify_type_names, this->notify_type); - return FAILED; + bad_length = TRUE; } break; } @@ -249,9 +283,23 @@ static status_t verify(private_notify_payload_t *this) { if (this->notification_data.len != 0) { - DBG1(DBG_ENC, "invalid %N notify", - notify_type_names, this->notify_type); - return FAILED; + bad_length = TRUE; + } + break; + } + case ADDITIONAL_IP4_ADDRESS: + { + if (this->notification_data.len != 4) + { + bad_length = TRUE; + } + break; + } + case ADDITIONAL_IP6_ADDRESS: + { + if (this->notification_data.len != 16) + { + bad_length = TRUE; } break; } @@ -259,6 +307,13 @@ static status_t verify(private_notify_payload_t *this) /* TODO: verify */ break; } + if (bad_length) + { + DBG1(DBG_ENC, "invalid notify data length for %N (%d)", + notify_type_names, this->notify_type, + this->notification_data.len); + return FAILED; + } return SUCCESS; } diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h index 431932631..231d0408d 100644 --- a/src/charon/encoding/payloads/notify_payload.h +++ b/src/charon/encoding/payloads/notify_payload.h @@ -65,6 +65,8 @@ enum notify_type_t { FAILED_CP_REQUIRED = 37, TS_UNACCEPTABLE = 38, INVALID_SELECTORS = 39, + UNACCEPTABLE_ADDRESSES = 40, + UNEXPECTED_NAT_DETECTED = 41, /* notify status messages */ INITIAL_CONTACT = 16384, SET_WINDOW_SIZE = 16385, @@ -102,6 +104,13 @@ enum notify_type_t { extern enum_name_t *notify_type_names; /** + * enum name for notify_type_t (shorter strings). + * + * @ingroup payloads + */ +extern enum_name_t *notify_type_short_names; + +/** * @brief Class representing an IKEv2-Notify Payload. * * The Notify Payload format is described in Draft section 3.10. diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index d82783b03..4770c7538 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -48,6 +48,8 @@ #include <processing/jobs/delete_child_sa_job.h> #include <processing/jobs/rekey_child_sa_job.h> #include <processing/jobs/acquire_job.h> +#include <processing/jobs/callback_job.h> +#include <processing/jobs/roam_job.h> /** kernel level protocol identifiers */ #define KERNEL_ESP 50 @@ -156,7 +158,7 @@ char* lookup_algorithm(kernel_algorithm_t *kernel_algo, } kernel_algo++; } - return NULL; + return NULL; } typedef struct route_entry_t route_entry_t; @@ -216,54 +218,61 @@ struct policy_entry_t { u_int refcount; }; -typedef struct vip_entry_t vip_entry_t; +typedef struct addr_entry_t addr_entry_t; /** - * Installed virtual ip + * IP address in an inface_entry_t */ -struct vip_entry_t { - /** Index of the interface the ip is bound to */ - u_int8_t if_index; +struct addr_entry_t { /** The ip address */ host_t *ip; - /** Number of times this IP is used */ + /** virtual IP managed by us */ + bool virtual; + + /** scope of the address */ + u_char scope; + + /** Number of times this IP is used, if virtual */ u_int refcount; }; /** - * destroy a vip_entry_t object + * destroy a addr_entry_t object */ -static void vip_entry_destroy(vip_entry_t *this) +static void addr_entry_destroy(addr_entry_t *this) { this->ip->destroy(this->ip); free(this); } -typedef struct address_entry_t address_entry_t; +typedef struct iface_entry_t iface_entry_t; /** - * an address found on the system, containg address and interface info + * A network interface on this system, containing addr_entry_t's */ -struct address_entry_t { - - /** address of this entry */ - host_t *host; +struct iface_entry_t { /** interface index */ int ifindex; - /** name of the index */ + /** name of the interface */ char ifname[IFNAMSIZ]; + + /** interface flags, as in netdevice(7) SIOCGIFFLAGS */ + u_int flags; + + /** list of addresses as host_t */ + linked_list_t *addrs; }; /** - * destroy an address entry + * destroy an interface entry */ -static void address_entry_destroy(address_entry_t *this) +static void iface_entry_destroy(iface_entry_t *this) { - this->host->destroy(this->host); + this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy); free(this); } @@ -279,29 +288,34 @@ struct private_kernel_interface_t { kernel_interface_t public; /** - * List of installed policies (kernel_entry_t) + * mutex to lock access to the various lists */ - linked_list_t *policies; + pthread_mutex_t mutex; /** - * Mutex locks access to policies + * List of installed policies (policy_entry_t) */ - pthread_mutex_t policies_mutex; + linked_list_t *policies; /** - * List of installed virtual IPs. (vip_entry_t) + * Cached list of interfaces and its adresses (iface_entry_t) */ - linked_list_t *vips; + linked_list_t *ifaces; /** - * Mutex to lock access to vips. + * iterator used in hook() + */ + iterator_t *hiter; + + /** + * job receiving netlink events */ - pthread_mutex_t vips_mutex; + callback_job_t *job; /** - * netlink xfrm socket to receive acquire and expire events + * current sequence number for netlink request */ - int socket_xfrm_events; + int seq; /** * Netlink xfrm socket (IPsec) @@ -309,14 +323,19 @@ struct private_kernel_interface_t { int socket_xfrm; /** + * netlink xfrm socket to receive acquire and expire events + */ + int socket_xfrm_events; + + /** * Netlink rt socket (routing) */ int socket_rt; /** - * Thread receiving events from kernel + * Netlink rt socket to receive address change events */ - pthread_t event_thread; + int socket_rt_events; }; /** @@ -442,107 +461,382 @@ static void add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data, } /** - * Receives events from kernel + * process a XFRM_MSG_ACQUIRE from kernel */ -static void receive_events(private_kernel_interface_t *this) +static void process_acquire(private_kernel_interface_t *this, struct nlmsghdr *hdr) { - charon->drop_capabilities(charon, TRUE); + u_int32_t reqid = 0; + job_t *job; + struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire); + size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl); + + if (RTA_OK(rtattr, rtsize)) + { + if (rtattr->rta_type == XFRMA_TMPL) + { + struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr); + reqid = tmpl->reqid; + } + } + if (reqid == 0) + { + DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found"); + return; + } + DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE"); + DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid %d", reqid); + job = (job_t*)acquire_job_create(reqid); + charon->processor->queue_job(charon->processor, job); +} - while(TRUE) +/** + * process a XFRM_MSG_EXPIRE from kernel + */ +static void process_expire(private_kernel_interface_t *this, struct nlmsghdr *hdr) +{ + job_t *job; + protocol_id_t protocol; + u_int32_t spi, reqid; + struct xfrm_user_expire *expire; + + expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr); + protocol = expire->state.id.proto == KERNEL_ESP ? PROTO_ESP : PROTO_AH; + spi = expire->state.id.spi; + reqid = expire->state.reqid; + + DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE"); + DBG1(DBG_KNL, "creating %s job for %N CHILD_SA 0x%x (reqid %d)", + expire->hard ? "delete" : "rekey", protocol_id_names, + protocol, ntohl(spi), reqid); + if (expire->hard) { - unsigned char response[512]; - struct nlmsghdr *hdr; - struct sockaddr_nl addr; - socklen_t addr_len = sizeof(addr); - int len; - - hdr = (struct nlmsghdr*)response; - len = recvfrom(this->socket_xfrm_events, response, sizeof(response), - 0, (struct sockaddr*)&addr, &addr_len); - if (len < 0) + job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi); + } + else + { + job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi); + } + charon->processor->queue_job(charon->processor, job); +} + +/** + * process RTM_NEWLINK/RTM_DELLINK from kernel + */ +static void process_link(private_kernel_interface_t *this, + struct nlmsghdr *hdr, bool event) +{ + struct ifinfomsg* msg = (struct ifinfomsg*)(NLMSG_DATA(hdr)); + struct rtattr *rta = IFLA_RTA(msg); + size_t rtasize = IFLA_PAYLOAD (hdr); + iterator_t *iterator; + iface_entry_t *current, *entry = NULL; + char *name = NULL; + bool update = FALSE; + + while(RTA_OK(rta, rtasize)) + { + switch (rta->rta_type) { - if (errno == EINTR) + case IFLA_IFNAME: + name = RTA_DATA(rta); + break; + } + rta = RTA_NEXT(rta, rtasize); + } + if (!name) + { + name = "(unknown)"; + } + + switch (hdr->nlmsg_type) + { + case RTM_NEWLINK: + { + if (msg->ifi_flags & IFF_LOOPBACK) + { /* ignore loopback interfaces */ + break; + } + iterator = this->ifaces->create_iterator_locked(this->ifaces, + &this->mutex); + while (iterator->iterate(iterator, (void**)¤t)) { - /* interrupted, try again */ - continue; + if (current->ifindex == msg->ifi_index) + { + entry = current; + break; + } + } + if (!entry) + { + entry = malloc_thing(iface_entry_t); + entry->ifindex = msg->ifi_index; + entry->flags = 0; + entry->addrs = linked_list_create(); + this->ifaces->insert_last(this->ifaces, entry); + } + memcpy(entry->ifname, name, IFNAMSIZ); + entry->ifname[IFNAMSIZ-1] = '\0'; + if (event) + { + if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP)) + { + update = TRUE; + DBG1(DBG_KNL, "interface %s activated", name); + } + if ((entry->flags & IFF_UP) && !(msg->ifi_flags & IFF_UP)) + { + update = TRUE; + DBG1(DBG_KNL, "interface %s deactivated", name); + } } - charon->kill(charon, "unable to receive netlink events"); + entry->flags = msg->ifi_flags; + iterator->destroy(iterator); + break; } - - if (!NLMSG_OK(hdr, len)) + case RTM_DELLINK: { - /* bad netlink message */ - continue; + iterator = this->ifaces->create_iterator_locked(this->ifaces, + &this->mutex); + while (iterator->iterate(iterator, (void**)¤t)) + { + if (current->ifindex == msg->ifi_index) + { + /* we do not remove it, as an address may be added to a + * "down" interface and we wan't to know that. */ + current->flags = msg->ifi_flags; + break; + } + } + iterator->destroy(iterator); + break; } + } + + /* send an update to all IKE_SAs */ + if (update && event) + { + charon->processor->queue_job(charon->processor, + (job_t*)roam_job_create(TRUE)); + } +} - if (addr.nl_pid != 0) +/** + * process RTM_NEWADDR/RTM_DELADDR from kernel + */ +static void process_addr(private_kernel_interface_t *this, + struct nlmsghdr *hdr, bool event) +{ + struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr)); + struct rtattr *rta = IFA_RTA(msg); + size_t rtasize = IFA_PAYLOAD (hdr); + host_t *host = NULL; + iterator_t *ifaces, *addrs; + iface_entry_t *iface; + addr_entry_t *addr; + chunk_t local = chunk_empty, address = chunk_empty; + bool update = FALSE, found = FALSE, changed = FALSE; + + while(RTA_OK(rta, rtasize)) + { + switch (rta->rta_type) { - /* not from kernel. not interested, try another one */ - continue; + case IFA_LOCAL: + local.ptr = RTA_DATA(rta); + local.len = RTA_PAYLOAD(rta); + break; + case IFA_ADDRESS: + address.ptr = RTA_DATA(rta); + address.len = RTA_PAYLOAD(rta); + break; } - - /* we handle ACQUIRE and EXPIRE messages directly */ - if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE) + rta = RTA_NEXT(rta, rtasize); + } + + /* For PPP interfaces, we need the IFA_LOCAL address, + * IFA_ADDRESS is the peers address. But IFA_LOCAL is + * not included in all cases (IPv6?), so fallback to IFA_ADDRESS. */ + if (local.ptr) + { + host = host_create_from_chunk(msg->ifa_family, local, 0); + } + else if (address.ptr) + { + host = host_create_from_chunk(msg->ifa_family, address, 0); + } + + if (host == NULL) + { /* bad family? */ + return; + } + + ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); + while (ifaces->iterate(ifaces, (void**)&iface)) + { + if (iface->ifindex == msg->ifa_index) { - u_int32_t reqid = 0; - job_t *job; - struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire); - size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl); - if (RTA_OK(rtattr, rtsize)) + addrs = iface->addrs->create_iterator(iface->addrs, TRUE); + while (addrs->iterate(addrs, (void**)&addr)) { - if (rtattr->rta_type == XFRMA_TMPL) + if (host->ip_equals(host, addr->ip)) { - struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr); - reqid = tmpl->reqid; + found = TRUE; + if (hdr->nlmsg_type == RTM_DELADDR) + { + changed = TRUE; + addrs->remove(addrs); + addr_entry_destroy(addr); + DBG1(DBG_KNL, "%H disappeared from %s", host, iface->ifname); + } } } - if (reqid == 0) + addrs->destroy(addrs); + + if (hdr->nlmsg_type == RTM_NEWADDR) { - DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found"); + if (!found) + { + found = TRUE; + changed = TRUE; + addr = malloc_thing(addr_entry_t); + addr->ip = host->clone(host); + addr->virtual = FALSE; + addr->refcount = 1; + addr->scope = msg->ifa_scope; + + iface->addrs->insert_last(iface->addrs, addr); + if (event) + { + DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname); + } + } } - else + if (found && (iface->flags & IFF_UP)) { - DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE"); - DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid %d", - reqid); - job = (job_t*)acquire_job_create(reqid); - charon->job_queue->add(charon->job_queue, job); + update = TRUE; } + break; + } + } + ifaces->destroy(ifaces); + host->destroy(host); + + /* send an update to all IKE_SAs */ + if (update && event && changed) + { + charon->processor->queue_job(charon->processor, + (job_t*)roam_job_create(TRUE)); + } +} + +/** + * Receives events from kernel + */ +static job_requeue_t receive_events(private_kernel_interface_t *this) +{ + char response[1024]; + struct nlmsghdr *hdr = (struct nlmsghdr*)response; + struct sockaddr_nl addr; + socklen_t addr_len = sizeof(addr); + int len, oldstate, maxfd, selected; + fd_set rfds; + + FD_ZERO(&rfds); + FD_SET(this->socket_xfrm_events, &rfds); + FD_SET(this->socket_rt_events, &rfds); + maxfd = max(this->socket_xfrm_events, this->socket_rt_events); + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + selected = select(maxfd + 1, &rfds, NULL, NULL, NULL); + pthread_setcancelstate(oldstate, NULL); + if (selected <= 0) + { + DBG1(DBG_KNL, "selecting on sockets failed: %s", strerror(errno)); + return JOB_REQUEUE_FAIR; + } + if (FD_ISSET(this->socket_xfrm_events, &rfds)) + { + selected = this->socket_xfrm_events; + } + else if (FD_ISSET(this->socket_rt_events, &rfds)) + { + selected = this->socket_rt_events; + } + else + { + return JOB_REQUEUE_DIRECT; + } + + len = recvfrom(selected, response, sizeof(response), MSG_DONTWAIT, + (struct sockaddr*)&addr, &addr_len); + if (len < 0) + { + switch (errno) + { + case EINTR: + /* interrupted, try again */ + return JOB_REQUEUE_DIRECT; + case EAGAIN: + /* no data ready, select again */ + return JOB_REQUEUE_DIRECT; + default: + DBG1(DBG_KNL, "unable to receive from xfrm event socket"); + sleep(1); + return JOB_REQUEUE_FAIR; } - else if (hdr->nlmsg_type == XFRM_MSG_EXPIRE) + } + if (addr.nl_pid != 0) + { /* not from kernel. not interested, try another one */ + return JOB_REQUEUE_DIRECT; + } + + while (NLMSG_OK(hdr, len)) + { + /* looks good so far, dispatch netlink message */ + if (selected == this->socket_xfrm_events) { - job_t *job; - protocol_id_t protocol; - u_int32_t spi, reqid; - struct xfrm_user_expire *expire; - - expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr); - protocol = expire->state.id.proto == KERNEL_ESP ? - PROTO_ESP : PROTO_AH; - spi = expire->state.id.spi; - reqid = expire->state.reqid; - - DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE"); - DBG1(DBG_KNL, "creating %s job for %N CHILD_SA 0x%x (reqid %d)", - expire->hard ? "delete" : "rekey", protocol_id_names, - protocol, ntohl(spi), reqid); - if (expire->hard) + switch (hdr->nlmsg_type) { - job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi); + case XFRM_MSG_ACQUIRE: + process_acquire(this, hdr); + break; + case XFRM_MSG_EXPIRE: + process_expire(this, hdr); + break; + default: + break; } - else + } + else if (selected == this->socket_rt_events) + { + switch (hdr->nlmsg_type) { - job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi); + case RTM_NEWADDR: + case RTM_DELADDR: + process_addr(this, hdr, TRUE); + break; + case RTM_NEWLINK: + case RTM_DELLINK: + process_link(this, hdr, TRUE); + break; + case RTM_NEWROUTE: + case RTM_DELROUTE: + charon->processor->queue_job(charon->processor, + (job_t*)roam_job_create(FALSE)); + break; + default: + break; } - charon->job_queue->add(charon->job_queue, job); } + hdr = NLMSG_NEXT(hdr, len); } + return JOB_REQUEUE_DIRECT; } /** * send a netlink message and wait for a reply */ -static status_t netlink_send(int socket, struct nlmsghdr *in, +static status_t netlink_send(private_kernel_interface_t *this, + int socket, struct nlmsghdr *in, struct nlmsghdr **out, size_t *out_len) { int len, addr_len; @@ -550,13 +844,9 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, chunk_t result = chunk_empty, tmp; struct nlmsghdr *msg, peek; - static int seq = 200; - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - + pthread_mutex_lock(&this->mutex); - pthread_mutex_lock(&mutex); - - in->nlmsg_seq = ++seq; + in->nlmsg_seq = ++this->seq; in->nlmsg_pid = getpid(); memset(&addr, 0, sizeof(addr)); @@ -576,7 +866,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, /* interrupted, try again */ continue; } - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&this->mutex); DBG1(DBG_KNL, "error sending to netlink socket: %s", strerror(errno)); return FAILED; } @@ -585,7 +875,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, while (TRUE) { - char buf[1024]; + char buf[4096]; tmp.len = sizeof(buf); tmp.ptr = buf; msg = (struct nlmsghdr*)tmp.ptr; @@ -603,28 +893,28 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, { if (errno == EINTR) { - DBG1(DBG_IKE, "got interrupted"); + DBG1(DBG_KNL, "got interrupted"); /* interrupted, try again */ continue; } - DBG1(DBG_IKE, "error reading from netlink socket: %s", strerror(errno)); - pthread_mutex_unlock(&mutex); + DBG1(DBG_KNL, "error reading from netlink socket: %s", strerror(errno)); + pthread_mutex_unlock(&this->mutex); return FAILED; } if (!NLMSG_OK(msg, len)) { - DBG1(DBG_IKE, "received corrupted netlink message"); - pthread_mutex_unlock(&mutex); + DBG1(DBG_KNL, "received corrupted netlink message"); + pthread_mutex_unlock(&this->mutex); return FAILED; } - if (msg->nlmsg_seq != seq) + if (msg->nlmsg_seq != this->seq) { - DBG1(DBG_IKE, "received invalid netlink sequence number"); - if (msg->nlmsg_seq < seq) + DBG1(DBG_KNL, "received invalid netlink sequence number"); + if (msg->nlmsg_seq < this->seq) { continue; } - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&this->mutex); return FAILED; } @@ -636,7 +926,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, len = recvfrom(socket, &peek, sizeof(peek), MSG_PEEK | MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len); - if (len == sizeof(peek) && peek.nlmsg_seq == seq) + if (len == sizeof(peek) && peek.nlmsg_seq == this->seq) { /* seems to be multipart */ continue; @@ -647,7 +937,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, *out_len = result.len; *out = (struct nlmsghdr*)clalloc(result.ptr, result.len); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&this->mutex); return SUCCESS; } @@ -655,12 +945,13 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, /** * send a netlink message and wait for its acknowlegde */ -static status_t netlink_send_ack(int socket, struct nlmsghdr *in) +static status_t netlink_send_ack(private_kernel_interface_t *this, + int socket, struct nlmsghdr *in) { struct nlmsghdr *out, *hdr; size_t len; - if (netlink_send(socket, in, &out, &len) != SUCCESS) + if (netlink_send(this, socket, in, &out, &len) != SUCCESS) { return FAILED; } @@ -697,132 +988,153 @@ static status_t netlink_send_ack(int socket, struct nlmsghdr *in) } /** - * Create a list of local addresses. + * Initialize a list of local addresses. */ -static linked_list_t *create_address_list(private_kernel_interface_t *this) +static status_t init_address_list(private_kernel_interface_t *this) { char request[BUFFER_SIZE]; - struct nlmsghdr *out, *hdr; + struct nlmsghdr *out, *current, *in; struct rtgenmsg *msg; size_t len; - linked_list_t *list; - - DBG2(DBG_IKE, "getting local address list"); + iterator_t *ifaces, *addrs; + iface_entry_t *iface; + addr_entry_t *addr; - list = linked_list_create(); + DBG1(DBG_KNL, "listening on interfaces:"); memset(&request, 0, sizeof(request)); - hdr = (struct nlmsghdr*)&request; - hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - hdr->nlmsg_type = RTM_GETADDR; - hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT; - msg = (struct rtgenmsg*)NLMSG_DATA(hdr); + in = (struct nlmsghdr*)&request; + in->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + in->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT; + msg = (struct rtgenmsg*)NLMSG_DATA(in); msg->rtgen_family = AF_UNSPEC; - - if (netlink_send(this->socket_rt, hdr, &out, &len) == SUCCESS) + + /* get all links */ + in->nlmsg_type = RTM_GETLINK; + if (netlink_send(this, this->socket_rt, in, &out, &len) != SUCCESS) { - hdr = out; - while (NLMSG_OK(hdr, len)) + return FAILED; + } + current = out; + while (NLMSG_OK(current, len)) + { + switch (current->nlmsg_type) { - switch (hdr->nlmsg_type) + case NLMSG_DONE: + break; + case RTM_NEWLINK: + process_link(this, current, FALSE); + /* fall through */ + default: + current = NLMSG_NEXT(current, len); + continue; + } + break; + } + free(out); + + /* get all interface addresses */ + in->nlmsg_type = RTM_GETADDR; + if (netlink_send(this, this->socket_rt, in, &out, &len) != SUCCESS) + { + return FAILED; + } + current = out; + while (NLMSG_OK(current, len)) + { + switch (current->nlmsg_type) + { + case NLMSG_DONE: + break; + case RTM_NEWADDR: + process_addr(this, current, FALSE); + /* fall through */ + default: + current = NLMSG_NEXT(current, len); + continue; + } + break; + } + free(out); + + ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); + while (ifaces->iterate(ifaces, (void**)&iface)) + { + if (iface->flags & IFF_UP) + { + DBG1(DBG_KNL, " %s", iface->ifname); + addrs = iface->addrs->create_iterator(iface->addrs, TRUE); + while (addrs->iterate(addrs, (void**)&addr)) { - case RTM_NEWADDR: - { - struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr)); - struct rtattr *rta = IFA_RTA(msg); - size_t rtasize = IFA_PAYLOAD (hdr); - host_t *host = NULL; - char *name = NULL; - chunk_t local = chunk_empty, address = chunk_empty; - - while(RTA_OK(rta, rtasize)) - { - switch (rta->rta_type) - { - case IFA_LOCAL: - local.ptr = RTA_DATA(rta); - local.len = RTA_PAYLOAD(rta); - break; - case IFA_ADDRESS: - address.ptr = RTA_DATA(rta); - address.len = RTA_PAYLOAD(rta); - break; - case IFA_LABEL: - name = RTA_DATA(rta); - break; - } - rta = RTA_NEXT(rta, rtasize); - } - - /* For PPP interfaces, we need the IFA_LOCAL address, - * IFA_ADDRESS is the peers address. But IFA_LOCAL is - * not included in all cases, so fallback to IFA_ADDRESS. */ - if (local.ptr) - { - host = host_create_from_chunk(msg->ifa_family, local, 0); - } - else if (address.ptr) - { - host = host_create_from_chunk(msg->ifa_family, address, 0); - } - - if (host) - { - address_entry_t *entry; - - entry = malloc_thing(address_entry_t); - entry->host = host; - entry->ifindex = msg->ifa_index; - if (name) - { - memcpy(entry->ifname, name, IFNAMSIZ); - } - else - { - strcpy(entry->ifname, "(unknown)"); - } - list->insert_last(list, entry); - } - hdr = NLMSG_NEXT(hdr, len); - continue; - } - default: - hdr = NLMSG_NEXT(hdr, len); - continue; - case NLMSG_DONE: - break; + DBG1(DBG_KNL, " %H", addr->ip); } - break; + addrs->destroy(addrs); } - free(out); } - else - { - DBG1(DBG_IKE, "unable to get local address list"); + ifaces->destroy(ifaces); + return SUCCESS; +} + +/** + * iterator hook to iterate over addrs + */ +static hook_result_t addr_hook(private_kernel_interface_t *this, + addr_entry_t *in, host_t **out) +{ + if (in->virtual) + { /* skip virtual interfaces added by us */ + return HOOK_SKIP; + } + if (in->scope >= RT_SCOPE_LINK) + { /* skip addresses with a unusable scope */ + return HOOK_SKIP; + } + *out = in->ip; + return HOOK_NEXT; +} + +/** + * iterator hook to iterate over ifaces + */ +static hook_result_t iface_hook(private_kernel_interface_t *this, + iface_entry_t *in, host_t **out) +{ + if (!(in->flags & IFF_UP)) + { /* skip interfaces not up */ + return HOOK_SKIP; } - return list; + if (this->hiter == NULL) + { + this->hiter = in->addrs->create_iterator(in->addrs, TRUE); + this->hiter->set_iterator_hook(this->hiter, + (iterator_hook_t*)addr_hook, this); + } + while (this->hiter->iterate(this->hiter, (void**)out)) + { + return HOOK_AGAIN; + } + this->hiter->destroy(this->hiter); + this->hiter = NULL; + return HOOK_SKIP; } /** - * Implements kernel_interface_t.create_address_list. + * Implements kernel_interface_t.create_address_iterator. */ -static linked_list_t *create_address_list_public(private_kernel_interface_t *this) +static iterator_t *create_address_iterator(private_kernel_interface_t *this) { - linked_list_t *result, *list; - address_entry_t *entry; + iterator_t *iterator; - result = linked_list_create(); - list = create_address_list(this); - while (list->remove_last(list, (void**)&entry) == SUCCESS) - { - result->insert_last(result, entry->host); - free(entry); - } - list->destroy(list); + /* This iterator is not only hooked, is is double-hooked. As we have stored + * our addresses in iface_entry->addr_entry->ip, we need to iterate the + * entries in each interface we iterate. This does the iface_hook. The + * addr_hook returns the ip instead of the addr_entry. */ - return result; + iterator = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); + iterator->set_iterator_hook(iterator, (iterator_hook_t*)iface_hook, this); + return iterator; } /** @@ -830,30 +1142,40 @@ static linked_list_t *create_address_list_public(private_kernel_interface_t *thi */ static char *get_interface_name(private_kernel_interface_t *this, host_t* ip) { - linked_list_t *list; - address_entry_t *entry; + iterator_t *ifaces, *addrs; + iface_entry_t *iface; + addr_entry_t *addr; char *name = NULL; - DBG2(DBG_IKE, "getting interface name for %H", ip); + DBG2(DBG_KNL, "getting interface name for %H", ip); - list = create_address_list(this); - while (!name && list->remove_last(list, (void**)&entry) == SUCCESS) + ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); + while (ifaces->iterate(ifaces, (void**)&iface)) { - if (ip->ip_equals(ip, entry->host)) + addrs = iface->addrs->create_iterator(iface->addrs, TRUE); + while (addrs->iterate(addrs, (void**)&addr)) + { + if (ip->ip_equals(ip, addr->ip)) + { + name = strdup(iface->ifname); + break; + } + } + addrs->destroy(addrs); + if (name) { - name = strdup(entry->ifname); + break; } - address_entry_destroy(entry); } - list->destroy_function(list, (void*)address_entry_destroy); + ifaces->destroy(ifaces); if (name) { - DBG2(DBG_IKE, "%H is on interface %s", ip, name); + DBG2(DBG_KNL, "%H is on interface %s", ip, name); } else { - DBG2(DBG_IKE, "%H is not a local address", ip); + DBG2(DBG_KNL, "%H is not a local address", ip); } return name; } @@ -865,13 +1187,14 @@ static char *get_interface_name(private_kernel_interface_t *this, host_t* ip) static status_t get_address_by_ts(private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip) { - address_entry_t *entry; + iterator_t *ifaces, *addrs; + iface_entry_t *iface; + addr_entry_t *addr; host_t *host; int family; - linked_list_t *list; bool found = FALSE; - DBG2(DBG_IKE, "getting a local address in traffic selector %R", ts); + DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts); /* if we have a family which includes localhost, we do not * search for an IP, we use the default */ @@ -890,29 +1213,38 @@ static status_t get_address_by_ts(private_kernel_interface_t *this, { *ip = host_create_any(family); host->destroy(host); - DBG2(DBG_IKE, "using host %H", *ip); + DBG2(DBG_KNL, "using host %H", *ip); return SUCCESS; } host->destroy(host); - list = create_address_list(this); - while (!found && list->remove_last(list, (void**)&entry) == SUCCESS) + ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); + while (ifaces->iterate(ifaces, (void**)&iface)) { - if (ts->includes(ts, entry->host)) + addrs = iface->addrs->create_iterator(iface->addrs, TRUE); + while (addrs->iterate(addrs, (void**)&addr)) { - found = TRUE; - *ip = entry->host->clone(entry->host); + if (ts->includes(ts, addr->ip)) + { + found = TRUE; + *ip = addr->ip->clone(addr->ip); + break; + } + } + addrs->destroy(addrs); + if (found) + { + break; } - address_entry_destroy(entry); } - list->destroy_function(list, (void*)address_entry_destroy); + ifaces->destroy(ifaces); if (!found) { - DBG1(DBG_IKE, "no local address found in traffic selector %R", ts); + DBG1(DBG_KNL, "no local address found in traffic selector %R", ts); return FAILED; } - DBG2(DBG_IKE, "using host %H", *ip); + DBG2(DBG_KNL, "using host %H", *ip); return SUCCESS; } @@ -921,26 +1253,36 @@ static status_t get_address_by_ts(private_kernel_interface_t *this, */ static int get_interface_index(private_kernel_interface_t *this, host_t* ip) { - linked_list_t *list; - address_entry_t *entry; + iterator_t *ifaces, *addrs; + iface_entry_t *iface; + addr_entry_t *addr; int ifindex = 0; - DBG2(DBG_IKE, "getting iface for %H", ip); + DBG2(DBG_KNL, "getting iface for %H", ip); - list = create_address_list(this); - while (!ifindex && list->remove_last(list, (void**)&entry) == SUCCESS) + ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); + while (ifaces->iterate(ifaces, (void**)&iface)) { - if (ip->ip_equals(ip, entry->host)) + addrs = iface->addrs->create_iterator(iface->addrs, TRUE); + while (addrs->iterate(addrs, (void**)&addr)) + { + if (ip->ip_equals(ip, addr->ip)) + { + ifindex = iface->ifindex; + break; + } + } + addrs->destroy(addrs); + if (ifindex) { - ifindex = entry->ifindex; + break; } - address_entry_destroy(entry); } - list->destroy_function(list, (void*)address_entry_destroy); - + ifaces->destroy(ifaces); + if (ifindex == 0) { - DBG1(DBG_IKE, "unable to get interface for %H", ip); + DBG1(DBG_KNL, "unable to get interface for %H", ip); } return ifindex; } @@ -975,7 +1317,7 @@ static status_t manage_ipaddr(private_kernel_interface_t *this, int nlmsg_type, add_attribute(hdr, IFA_LOCAL, chunk, sizeof(request)); - return netlink_send_ack(this->socket_rt, hdr); + return netlink_send_ack(this, this->socket_rt, hdr); } /** @@ -1036,107 +1378,206 @@ static status_t manage_srcroute(private_kernel_interface_t *this, int nlmsg_type chunk.len = sizeof(route->if_index); add_attribute(hdr, RTA_OIF, chunk, sizeof(request)); - return netlink_send_ack(this->socket_rt, hdr); + return netlink_send_ack(this, this->socket_rt, hdr); } - /** - * Implementation of kernel_interface_t.add_ip. + * Get the nexthop gateway for dest; or the source addr if gateway = FALSE */ -static status_t add_ip(private_kernel_interface_t *this, - host_t *virtual_ip, host_t *iface_ip) +static host_t* get_addr(private_kernel_interface_t *this, + host_t *dest, bool gateway) { - int targetif; - vip_entry_t *listed; - iterator_t *iterator; + unsigned char request[BUFFER_SIZE]; + struct nlmsghdr *hdr, *out, *current; + struct rtmsg *msg; + chunk_t chunk; + size_t len; + host_t *addr = NULL; + + DBG2(DBG_KNL, "getting address to reach %H", dest); + + memset(&request, 0, sizeof(request)); - DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip); + hdr = (struct nlmsghdr*)request; + hdr->nlmsg_flags = NLM_F_REQUEST; + hdr->nlmsg_type = RTM_GETROUTE; + hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - targetif = get_interface_index(this, iface_ip); - if (targetif == 0) + msg = (struct rtmsg*)NLMSG_DATA(hdr); + msg->rtm_family = dest->get_family(dest); + msg->rtm_dst_len = msg->rtm_family == AF_INET ? 32 : 128; + msg->rtm_table = RT_TABLE_MAIN; + msg->rtm_protocol = RTPROT_STATIC; + msg->rtm_type = RTN_UNICAST; + msg->rtm_scope = RT_SCOPE_UNIVERSE; + + chunk = dest->get_address(dest); + add_attribute(hdr, RTA_DST, chunk, sizeof(request)); + + if (netlink_send(this, this->socket_rt, hdr, &out, &len) != SUCCESS) { - DBG1(DBG_KNL, "unable to add virtual IP %H, no iface found for %H", - virtual_ip, iface_ip); - return FAILED; + DBG1(DBG_KNL, "getting address to %H failed", dest); + return NULL; } - - /* beware of deadlocks (e.g. send/receive packets while holding the lock) */ - iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex)); - while (iterator->iterate(iterator, (void**)&listed)) + current = out; + while (NLMSG_OK(current, len)) { - if (listed->if_index == targetif && - virtual_ip->ip_equals(virtual_ip, listed->ip)) + switch (current->nlmsg_type) { - listed->refcount++; - iterator->destroy(iterator); - DBG2(DBG_KNL, "virtual IP %H already added to iface %d reusing it", - virtual_ip, targetif); - return SUCCESS; + case NLMSG_DONE: + break; + case RTM_NEWROUTE: + { + struct rtattr *rta; + size_t rtasize; + + msg = (struct rtmsg*)(NLMSG_DATA(current)); + rta = RTM_RTA(msg); + rtasize = RTM_PAYLOAD(current); + while(RTA_OK(rta, rtasize)) + { + if ((rta->rta_type == RTA_PREFSRC && !gateway) || + (rta->rta_type == RTA_GATEWAY && gateway)) + { + chunk.ptr = RTA_DATA(rta); + chunk.len = RTA_PAYLOAD(rta); + addr = host_create_from_chunk(msg->rtm_family, + chunk, 0); + break; + } + rta = RTA_NEXT(rta, rtasize); + } + break; + } + default: + current = NLMSG_NEXT(current, len); + continue; } + break; } - iterator->destroy(iterator); + free(out); + if (addr == NULL) + { + DBG2(DBG_KNL, "no route found to %H", dest); + } + return addr; +} + +/** + * Implementation of kernel_interface_t.get_source_addr. + */ +static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest) +{ + return get_addr(this, dest, FALSE); +} - if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL, - targetif, virtual_ip) == SUCCESS) +/** + * Implementation of kernel_interface_t.add_ip. + */ +static status_t add_ip(private_kernel_interface_t *this, + host_t *virtual_ip, host_t *iface_ip) +{ + iface_entry_t *iface; + addr_entry_t *addr; + iterator_t *addrs, *ifaces; + + DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip); + + ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); + while (ifaces->iterate(ifaces, (void**)&iface)) { - listed = malloc_thing(vip_entry_t); - listed->ip = virtual_ip->clone(virtual_ip); - listed->if_index = targetif; - listed->refcount = 1; - this->vips->insert_last(this->vips, listed); - DBG2(DBG_KNL, "virtual IP %H added to iface %d", - virtual_ip, targetif); - return SUCCESS; + bool iface_found = FALSE; + + addrs = iface->addrs->create_iterator(iface->addrs, TRUE); + while (addrs->iterate(addrs, (void**)&addr)) + { + if (iface_ip->ip_equals(iface_ip, addr->ip)) + { + iface_found = TRUE; + } + else if (virtual_ip->ip_equals(virtual_ip, addr->ip)) + { + addr->refcount++; + DBG2(DBG_KNL, "virtual IP %H already installed on %s", + virtual_ip, iface->ifname); + addrs->destroy(addrs); + ifaces->destroy(ifaces); + return SUCCESS; + } + } + addrs->destroy(addrs); + + if (iface_found) + { + int ifindex = iface->ifindex; + ifaces->destroy(ifaces); + if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL, + ifindex, virtual_ip) == SUCCESS) + { + addr = malloc_thing(addr_entry_t); + addr->ip = virtual_ip->clone(virtual_ip); + addr->refcount = 1; + addr->virtual = TRUE; + addr->scope = RT_SCOPE_UNIVERSE; + pthread_mutex_lock(&this->mutex); + iface->addrs->insert_last(iface->addrs, addr); + pthread_mutex_unlock(&this->mutex); + return SUCCESS; + } + DBG2(DBG_KNL, "adding virtual IP %H failed", virtual_ip); + return FAILED; + + } + } + ifaces->destroy(ifaces); - DBG2(DBG_KNL, "unable to add virtual IP %H to iface %d", - virtual_ip, targetif); + DBG2(DBG_KNL, "interface address %H not found, unable to install" + "virtual IP %H", iface_ip, virtual_ip); return FAILED; } /** * Implementation of kernel_interface_t.del_ip. */ -static status_t del_ip(private_kernel_interface_t *this, - host_t *virtual_ip, host_t *iface_ip) +static status_t del_ip(private_kernel_interface_t *this, host_t *virtual_ip) { - int targetif; - vip_entry_t *listed; - iterator_t *iterator; + iface_entry_t *iface; + addr_entry_t *addr; + iterator_t *addrs, *ifaces; DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip); - - targetif = get_interface_index(this, iface_ip); - if (targetif == 0) - { - DBG1(DBG_KNL, "unable to delete virtual IP %H, no iface found for %H", - virtual_ip, iface_ip); - return FAILED; - } - - /* beware of deadlocks (e.g. send/receive packets while holding the lock) */ - iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex)); - while (iterator->iterate(iterator, (void**)&listed)) + + ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); + while (ifaces->iterate(ifaces, (void**)&iface)) { - if (listed->if_index == targetif && - virtual_ip->ip_equals(virtual_ip, listed->ip)) + addrs = iface->addrs->create_iterator(iface->addrs, TRUE); + while (addrs->iterate(addrs, (void**)&addr)) { - listed->refcount--; - if (listed->refcount == 0) + if (virtual_ip->ip_equals(virtual_ip, addr->ip)) { - iterator->remove(iterator); - vip_entry_destroy(listed); - iterator->destroy(iterator); - return manage_ipaddr(this, RTM_DELADDR, 0, targetif, virtual_ip); + int ifindex = iface->ifindex; + addr->refcount--; + if (addr->refcount == 0) + { + addrs->remove(addrs); + addrs->destroy(addrs); + ifaces->destroy(ifaces); + addr_entry_destroy(addr); + return manage_ipaddr(this, RTM_DELADDR, 0, + ifindex, virtual_ip); + } + DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting", + virtual_ip); + addrs->destroy(addrs); + ifaces->destroy(ifaces); + return SUCCESS; } - iterator->destroy(iterator); - DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting", - virtual_ip); - return SUCCESS; } + addrs->destroy(addrs); } - iterator->destroy(iterator); - + ifaces->destroy(ifaces); + DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip); return FAILED; } @@ -1174,7 +1615,7 @@ static status_t get_spi(private_kernel_interface_t *this, userspi->min = 0xc0000000; userspi->max = 0xcFFFFFFF; - if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) + if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { hdr = out; while (NLMSG_OK(hdr, len)) @@ -1226,7 +1667,7 @@ static status_t add_sa(private_kernel_interface_t *this, protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, algorithm_t *enc_alg, algorithm_t *int_alg, - prf_plus_t *prf_plus, natt_conf_t *natt, mode_t mode, + prf_plus_t *prf_plus, mode_t mode, bool encap, bool replace) { unsigned char request[BUFFER_SIZE]; @@ -1324,7 +1765,7 @@ static status_t add_sa(private_kernel_interface_t *this, /* TODO: add IPComp here */ - if (natt) + if (encap) { rthdr->rta_type = XFRMA_ENCAP; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); @@ -1335,11 +1776,11 @@ static status_t add_sa(private_kernel_interface_t *this, return FAILED; } - struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); - encap->encap_type = UDP_ENCAP_ESPINUDP; - encap->encap_sport = htons(natt->sport); - encap->encap_dport = htons(natt->dport); - memset(&encap->encap_oa, 0, sizeof (xfrm_address_t)); + struct xfrm_encap_tmpl* tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); + tmpl->encap_type = UDP_ENCAP_ESPINUDP; + tmpl->encap_sport = htons(src->get_port(src)); + tmpl->encap_dport = htons(dst->get_port(dst)); + memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); /* encap_oa could probably be derived from the * traffic selectors [rfc4306, p39]. In the netlink kernel implementation * pluto does the same as we do here but it uses encap_oa in the @@ -1352,9 +1793,9 @@ static status_t add_sa(private_kernel_interface_t *this, rthdr = XFRM_RTA_NEXT(rthdr); } - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { - DBG1(DBG_KNL, "unalbe to add SAD entry with SPI 0x%x", spi); + DBG1(DBG_KNL, "unable to add SAD entry with SPI 0x%x", spi); return FAILED; } return SUCCESS; @@ -1364,21 +1805,24 @@ static status_t add_sa(private_kernel_interface_t *this, * Implementation of kernel_interface_t.update_sa. */ static status_t update_sa(private_kernel_interface_t *this, - host_t *src, host_t *dst, - host_t *new_src, host_t *new_dst, - host_diff_t src_changes, host_diff_t dst_changes, - u_int32_t spi, protocol_id_t protocol) + u_int32_t spi, protocol_id_t protocol, + host_t *src, host_t *dst, + host_t *new_src, host_t *new_dst, bool encap) { - unsigned char request[BUFFER_SIZE]; + unsigned char request[BUFFER_SIZE], *pos; struct nlmsghdr *hdr, *out = NULL; struct xfrm_usersa_id *sa_id; - struct xfrm_usersa_info *sa = NULL; + struct xfrm_usersa_info *out_sa = NULL, *sa; size_t len; + struct rtattr *rta; + size_t rtasize; + struct xfrm_encap_tmpl* tmpl = NULL; memset(&request, 0, sizeof(request)); - DBG2(DBG_KNL, "querying SAD entry with SPI 0x%x", spi); + DBG2(DBG_KNL, "querying SAD entry with SPI 0x%x for update", spi); + /* query the exisiting SA first */ hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST; hdr->nlmsg_type = XFRM_MSG_GETSA; @@ -1390,7 +1834,7 @@ static status_t update_sa(private_kernel_interface_t *this, sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); - if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) + if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { hdr = out; while (NLMSG_OK(hdr, len)) @@ -1399,7 +1843,7 @@ static status_t update_sa(private_kernel_interface_t *this, { case XFRM_MSG_NEWSA: { - sa = NLMSG_DATA(hdr); + out_sa = NLMSG_DATA(hdr); break; } case NLMSG_ERROR: @@ -1418,59 +1862,76 @@ static status_t update_sa(private_kernel_interface_t *this, break; } } - if (sa == NULL) + if (out_sa == NULL || + this->public.del_sa(&this->public, dst, spi, protocol) != SUCCESS) { DBG1(DBG_KNL, "unable to update SAD entry with SPI 0x%x", spi); free(out); return FAILED; } - DBG2(DBG_KNL, "updating SAD entry with SPI 0x%x", spi); + DBG2(DBG_KNL, "updating SAD entry with SPI 0x%x from %#H..%#H to %#H..%#H", + spi, src, dst, new_src, new_dst); - hdr = out; + /* copy over the SA from out to request */ + hdr = (struct nlmsghdr*)request; + memcpy(hdr, out, min(out->nlmsg_len, sizeof(request))); hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - hdr->nlmsg_type = XFRM_MSG_UPDSA; + hdr->nlmsg_type = XFRM_MSG_NEWSA; + hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); + sa = NLMSG_DATA(hdr); + sa->family = new_dst->get_family(new_dst); - if (src_changes & HOST_DIFF_ADDR) + if (!src->ip_equals(src, new_src)) { host2xfrm(new_src, &sa->saddr); } - - if (dst_changes & HOST_DIFF_ADDR) + if (!dst->ip_equals(dst, new_dst)) { - hdr->nlmsg_type = XFRM_MSG_NEWSA; host2xfrm(new_dst, &sa->id.daddr); } - if (src_changes & HOST_DIFF_PORT || dst_changes & HOST_DIFF_PORT) + rta = XFRM_RTA(out, struct xfrm_usersa_info); + rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info); + pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info); + while(RTA_OK(rta, rtasize)) { - struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_usersa_info); - size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_usersa_info); - while (RTA_OK(rtattr, rtsize)) + /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ + if (rta->rta_type != XFRMA_ENCAP || encap) { - if (rtattr->rta_type == XFRMA_ENCAP) - { - struct xfrm_encap_tmpl* encap; - encap = (struct xfrm_encap_tmpl*)RTA_DATA(rtattr); - encap->encap_sport = ntohs(new_src->get_port(new_src)); - encap->encap_dport = ntohs(new_dst->get_port(new_dst)); - break; - } - rtattr = RTA_NEXT(rtattr, rtsize); + if (rta->rta_type == XFRMA_ENCAP) + { /* update encap tmpl */ + tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); + tmpl->encap_sport = ntohs(new_src->get_port(new_src)); + tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); + } + memcpy(pos, rta, rta->rta_len); + pos += rta->rta_len; + hdr->nlmsg_len += rta->rta_len; } + rta = RTA_NEXT(rta, rtasize); + } + if (tmpl == NULL && encap) + { /* add tmpl if we are enabling it */ + rta = (struct rtattr*)pos; + rta->rta_type = XFRMA_ENCAP; + rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); + hdr->nlmsg_len += rta->rta_len; + tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); + tmpl->encap_type = UDP_ENCAP_ESPINUDP; + tmpl->encap_sport = ntohs(new_src->get_port(new_src)); + tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); + memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); } - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { - DBG1(DBG_KNL, "unalbe to update SAD entry with SPI 0x%x", spi); + DBG1(DBG_KNL, "unable to update SAD entry with SPI 0x%x", spi); free(out); return FAILED; } free(out); - if (dst_changes & HOST_DIFF_ADDR) - { - return this->public.del_sa(&this->public, dst, spi, protocol); - } return SUCCESS; } @@ -1501,7 +1962,7 @@ static status_t query_sa(private_kernel_interface_t *this, host_t *dst, sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); - if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) + if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { hdr = out; while (NLMSG_OK(hdr, len)) @@ -1567,9 +2028,9 @@ static status_t del_sa(private_kernel_interface_t *this, host_t *dst, sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { - DBG1(DBG_KNL, "unalbe to delete SAD entry with SPI 0x%x", spi); + DBG1(DBG_KNL, "unable to delete SAD entry with SPI 0x%x", spi); return FAILED; } DBG2(DBG_KNL, "deleted SAD entry with SPI 0x%x", spi); @@ -1584,8 +2045,7 @@ static status_t add_policy(private_kernel_interface_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, protocol_id_t protocol, - u_int32_t reqid, bool high_prio, mode_t mode, - bool update) + u_int32_t reqid, bool high_prio, mode_t mode) { iterator_t *iterator; policy_entry_t *current, *policy; @@ -1601,7 +2061,7 @@ static status_t add_policy(private_kernel_interface_t *this, policy->direction = direction; /* find the policy, which matches EXACTLY */ - pthread_mutex_lock(&this->policies_mutex); + pthread_mutex_lock(&this->mutex); iterator = this->policies->create_iterator(this->policies, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { @@ -1609,12 +2069,9 @@ static status_t add_policy(private_kernel_interface_t *this, policy->direction == current->direction) { /* use existing policy */ - if (!update) - { - current->refcount++; - DBG2(DBG_KNL, "policy %R===%R already exists, increasing ", - "refcount", src_ts, dst_ts); - } + current->refcount++; + DBG2(DBG_KNL, "policy %R===%R already exists, increasing ", + "refcount", src_ts, dst_ts); free(policy); policy = current; found = TRUE; @@ -1646,7 +2103,7 @@ static status_t add_policy(private_kernel_interface_t *this, policy_info->priority -= policy->sel.sport_mask ? 1 : 0; policy_info->action = XFRM_POLICY_ALLOW; policy_info->share = XFRM_SHARE_ANY; - pthread_mutex_unlock(&this->policies_mutex); + pthread_mutex_unlock(&this->mutex); /* policies don't expire */ policy_info->lft.soft_byte_limit = XFRM_INF; @@ -1680,7 +2137,7 @@ static status_t add_policy(private_kernel_interface_t *this, host2xfrm(src, &tmpl->saddr); host2xfrm(dst, &tmpl->id.daddr); - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unable to add policy %R===%R", src_ts, dst_ts); return FAILED; @@ -1698,7 +2155,13 @@ static status_t add_policy(private_kernel_interface_t *this, policy->route = malloc_thing(route_entry_t); if (get_address_by_ts(this, dst_ts, &policy->route->src_ip) == SUCCESS) { - policy->route->gateway = dst->clone(dst); + /* if we have a gateway (via), we use it. If it's direct, we + * use the peers address (which is src, as we are in POLICY_FWD).*/ + policy->route->gateway = get_addr(this, src, TRUE); + if (policy->route->gateway == NULL) + { + policy->route->gateway = src->clone(src); + } policy->route->if_index = get_interface_index(this, dst); policy->route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); memcpy(policy->route->dst_net.ptr, &policy->sel.saddr, policy->route->dst_net.len); @@ -1750,7 +2213,7 @@ static status_t query_policy(private_kernel_interface_t *this, policy_id->sel = ts2selector(src_ts, dst_ts); policy_id->dir = direction; - if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) + if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { hdr = out; while (NLMSG_OK(hdr, len)) @@ -1814,8 +2277,7 @@ static status_t del_policy(private_kernel_interface_t *this, policy.direction = direction; /* find the policy */ - pthread_mutex_lock(&this->policies_mutex); - iterator = this->policies->create_iterator(this->policies, TRUE); + iterator = this->policies->create_iterator_locked(this->policies, &this->mutex); while (iterator->iterate(iterator, (void**)¤t)) { if (memcmp(¤t->sel, &policy.sel, sizeof(struct xfrm_selector)) == 0 && @@ -1827,7 +2289,6 @@ static status_t del_policy(private_kernel_interface_t *this, /* is used by more SAs, keep in kernel */ DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); iterator->destroy(iterator); - pthread_mutex_unlock(&this->policies_mutex); return SUCCESS; } /* remove if last reference */ @@ -1836,7 +2297,6 @@ static status_t del_policy(private_kernel_interface_t *this, } } iterator->destroy(iterator); - pthread_mutex_unlock(&this->policies_mutex); if (!to_delete) { DBG1(DBG_KNL, "deleting policy %R===%R failed, not found", src_ts, dst_ts); @@ -1857,7 +2317,7 @@ static status_t del_policy(private_kernel_interface_t *this, route = to_delete->route; free(to_delete); - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unable to delete policy %R===%R", src_ts, dst_ts); return FAILED; @@ -1880,13 +2340,13 @@ static status_t del_policy(private_kernel_interface_t *this, */ static void destroy(private_kernel_interface_t *this) { - pthread_cancel(this->event_thread); - pthread_join(this->event_thread, NULL); + this->job->cancel(this->job); close(this->socket_xfrm_events); close(this->socket_xfrm); + close(this->socket_rt_events); close(this->socket_rt); - this->vips->destroy(this->vips); this->policies->destroy(this->policies); + this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy); free(this); } @@ -1900,41 +2360,29 @@ kernel_interface_t *kernel_interface_create() /* public functions */ this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; - this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,mode_t,bool))add_sa; - this->public.update_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_diff_t,host_diff_t))update_sa; + this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,mode_t,bool,bool))add_sa; + this->public.update_sa = (status_t(*)(kernel_interface_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa; this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa; this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa; - this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t,bool))add_policy; + this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t))add_policy; this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy; this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy; - this->public.get_interface = (char*(*)(kernel_interface_t*,host_t*))get_interface_name; - this->public.create_address_list = (linked_list_t*(*)(kernel_interface_t*))create_address_list_public; + this->public.create_address_iterator = (iterator_t*(*)(kernel_interface_t*))create_address_iterator; + this->public.get_source_addr = (host_t*(*)(kernel_interface_t*, host_t *dest))get_source_addr; this->public.add_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) add_ip; - this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) del_ip; + this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*)) del_ip; this->public.destroy = (void(*)(kernel_interface_t*)) destroy; /* private members */ - this->vips = linked_list_create(); this->policies = linked_list_create(); - pthread_mutex_init(&this->policies_mutex,NULL); - pthread_mutex_init(&this->vips_mutex,NULL); + this->ifaces = linked_list_create(); + this->hiter = NULL; + this->seq = 200; + pthread_mutex_init(&this->mutex,NULL); + memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; - addr.nl_groups = 0; - - /* create and bind XFRM socket */ - this->socket_xfrm = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); - if (this->socket_xfrm <= 0) - { - charon->kill(charon, "unable to create XFRM netlink socket"); - } - - if (bind(this->socket_xfrm, (struct sockaddr*)&addr, sizeof(addr))) - { - charon->kill(charon, "unable to bind XFRM netlink socket"); - } /* create and bind RT socket */ this->socket_rt = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); @@ -1942,33 +2390,58 @@ kernel_interface_t *kernel_interface_create() { charon->kill(charon, "unable to create RT netlink socket"); } - + addr.nl_groups = 0; if (bind(this->socket_rt, (struct sockaddr*)&addr, sizeof(addr))) { charon->kill(charon, "unable to bind RT netlink socket"); } + /* create and bind RT socket for events (address/interface/route changes) */ + this->socket_rt_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (this->socket_rt_events <= 0) + { + charon->kill(charon, "unable to create RT event socket"); + } + addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | + RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_LINK; + if (bind(this->socket_rt_events, (struct sockaddr*)&addr, sizeof(addr))) + { + charon->kill(charon, "unable to bind RT event socket"); + } + + /* create and bind XFRM socket */ + this->socket_xfrm = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); + if (this->socket_xfrm <= 0) + { + charon->kill(charon, "unable to create XFRM netlink socket"); + } + addr.nl_groups = 0; + if (bind(this->socket_xfrm, (struct sockaddr*)&addr, sizeof(addr))) + { + charon->kill(charon, "unable to bind XFRM netlink socket"); + } + /* create and bind XFRM socket for ACQUIRE & EXPIRE */ - addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); if (this->socket_xfrm_events <= 0) { charon->kill(charon, "unable to create XFRM event socket"); } - + addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr))) { charon->kill(charon, "unable to bind XFRM event socket"); } - /* create a thread receiving ACQUIRE & EXPIRE events */ - if (pthread_create(&this->event_thread, NULL, - (void*(*)(void*))receive_events, this)) + this->job = callback_job_create((callback_job_cb_t)receive_events, + this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); + + if (init_address_list(this) != SUCCESS) { - charon->kill(charon, "unable to create xfrm event dispatcher thread"); + charon->kill(charon, "unable to get interface list"); } return &this->public; } -/* vim: set ts=4 sw=4 noet: */ diff --git a/src/charon/kernel/kernel_interface.h b/src/charon/kernel/kernel_interface.h index 2a3eaff7a..256c20797 100644 --- a/src/charon/kernel/kernel_interface.h +++ b/src/charon/kernel/kernel_interface.h @@ -25,7 +25,6 @@ #ifndef KERNEL_INTERFACE_H_ #define KERNEL_INTERFACE_H_ -typedef struct natt_conf_t natt_conf_t; typedef enum policy_dir_t policy_dir_t; typedef struct kernel_interface_t kernel_interface_t; @@ -33,17 +32,6 @@ typedef struct kernel_interface_t kernel_interface_t; #include <crypto/prf_plus.h> #include <encoding/payloads/proposal_substructure.h> -/** - * Configuration for NAT-T - * - * @ingroup kernel - */ -struct natt_conf_t { - /** source port to use for UDP-encapsulated packets */ - u_int16_t sport; - /** dest port to use for UDP-encapsulated packets */ - u_int16_t dport; -}; /** * Direction of a policy. These are equal to those @@ -121,8 +109,8 @@ struct kernel_interface_t { * @param enc_alg Algorithm to use for encryption (ESP only) * @param int_alg Algorithm to use for integrity protection * @param prf_plus PRF to derive keys from - * @param natt NAT-T Configuration, or NULL of no NAT-T used * @param mode mode of the SA (tunnel, transport) + * @param encap enable UDP encapsulation for NAT traversal * @param replace Should an already installed SA be updated? * @return * - SUCCESS @@ -133,8 +121,8 @@ struct kernel_interface_t { protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, algorithm_t *enc_alg, algorithm_t *int_alg, - prf_plus_t *prf_plus, natt_conf_t *natt, - mode_t mode, bool update); + prf_plus_t *prf_plus, mode_t mode, bool encap, + bool update); /** * @brief Update the hosts on an installed SA. @@ -145,21 +133,21 @@ struct kernel_interface_t { * create a new SA and delete the old one. * * @param this calling object - * @param dst destination address for this SA * @param spi SPI of the SA * @param protocol protocol for this SA (ESP/AH) - * @param new_src new source address for this SA - * @param new_dst new destination address for this SA - * @param src_changes changes in src - * @param dst_changes changes in dst + * @param src current source address + * @param dst current destination address + * @param new_src new source address + * @param new_dst new destination address + * @param encap use UDP encapsulation * @return * - SUCCESS * - FAILED if kernel comm failed */ - status_t (*update_sa)(kernel_interface_t *this, host_t *dst, u_int32_t spi, - protocol_id_t protocol, - host_t *new_src, host_t *new_dst, - host_diff_t src_changes, host_diff_t dst_changes); + status_t (*update_sa)(kernel_interface_t *this, + u_int32_t spi, protocol_id_t protocol, + host_t *src, host_t *dst, + host_t *new_src, host_t *new_dst, bool encap); /** * @brief Query the use time of an SA. @@ -198,10 +186,6 @@ struct kernel_interface_t { * * A policy is always associated to an SA. Traffic which matches a * policy is handled by the SA with the same reqid. - * If the update flag is set, the policy is updated with the new - * src/dst addresses. - * If the update flag is not set, but a such policy is already in the - * kernel, the reference count to this policy is increased. * * @param this calling object * @param src source address of SA @@ -213,7 +197,6 @@ struct kernel_interface_t { * @param reqid uniqe ID of an SA to use to enforce policy * @param high_prio if TRUE, uses a higher priority than any with FALSE * @param mode mode of SA (tunnel, transport) - * @param update update an existing policy, if TRUE * @return * - SUCCESS * - FAILED if kernel comm failed @@ -223,8 +206,7 @@ struct kernel_interface_t { traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, protocol_id_t protocol, - u_int32_t reqid, bool high_prio, - mode_t mode, bool update); + u_int32_t reqid, bool high_prio, mode_t mode); /** * @brief Query the use time of a policy. @@ -268,6 +250,18 @@ struct kernel_interface_t { policy_dir_t direction); /** + * @brief Get our outgoing source address for a destination. + * + * Does a route lookup to get the source address used to reach dest. + * The returned host is allocated and must be destroyed. + * + * @param this calling object + * @param dest target destination address + * @return outgoing source address, NULL if unreachable + */ + host_t* (*get_source_addr)(kernel_interface_t *this, host_t *dest); + + /** * @brief Get the interface name of a local address. * * @param this calling object @@ -277,12 +271,16 @@ struct kernel_interface_t { char* (*get_interface) (kernel_interface_t *this, host_t *host); /** - * @brief Creates a list of all local addresses. + * @brief Creates an iterator over all local addresses. + * + * This function blocks an internal cached address list until the + * iterator gets destroyed. + * These hosts are read-only, do not modify or free. * * @param this calling object - * @return allocated list with host_t objects + * @return iterator over host_t's */ - linked_list_t *(*create_address_list) (kernel_interface_t *this); + iterator_t *(*create_address_iterator) (kernel_interface_t *this); /** * @brief Add a virtual IP to an interface. @@ -309,13 +307,11 @@ struct kernel_interface_t { * * @param this calling object * @param virtual_ip virtual ip address to assign - * @param iface_ip IP of an interface to remove virtual IP from * @return * - SUCCESS * - FAILED if kernel comm failed */ - status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip, - host_t *iface_ip); + status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip); /** * @brief Destroys a kernel_interface object. diff --git a/src/charon/network/receiver.c b/src/charon/network/receiver.c index 9b4bf71ac..1de1dd3d2 100644 --- a/src/charon/network/receiver.c +++ b/src/charon/network/receiver.c @@ -30,9 +30,9 @@ #include <daemon.h> #include <network/socket.h> #include <network/packet.h> -#include <processing/job_queue.h> #include <processing/jobs/job.h> #include <processing/jobs/process_message_job.h> +#include <processing/jobs/callback_job.h> /** length of the full cookie, including time (u_int32_t + SHA1()) */ #define COOKIE_LENGTH 24 @@ -56,12 +56,17 @@ struct private_receiver_t { /** * Public part of a receiver_t object. */ - receiver_t public; + receiver_t public; + + /** + * Threads job receiving packets + */ + callback_job_t *job; - /** - * Assigned thread. - */ - pthread_t assigned_thread; + /** + * Assigned thread. + */ + pthread_t assigned_thread; /** * current secret to use for cookie calculation @@ -245,94 +250,84 @@ static bool peer_to_aggressive(private_receiver_t *this, message_t *message) /** * Implementation of receiver_t.receive_packets. */ -static void receive_packets(private_receiver_t *this) +static job_requeue_t receive_packets(private_receiver_t *this) { packet_t *packet; message_t *message; job_t *job; - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - DBG1(DBG_NET, "receiver thread running, thread_ID: %06u", - (int)pthread_self()); + /* read in a packet */ + if (charon->socket->receive(charon->socket, &packet) != SUCCESS) + { + DBG2(DBG_NET, "receiving from socket failed!"); + return JOB_REQUEUE_FAIR; + } - charon->drop_capabilities(charon, TRUE); + /* parse message header */ + message = message_create_from_packet(packet); + if (message->parse_header(message) != SUCCESS) + { + DBG1(DBG_NET, "received invalid IKE header from %H - ignored", + packet->get_source(packet)); + message->destroy(message); + return JOB_REQUEUE_DIRECT; + } - while (TRUE) + /* check IKE major version */ + if (message->get_major_version(message) != IKE_MAJOR_VERSION) { - /* read in a packet */ - if (charon->socket->receive(charon->socket, &packet) != SUCCESS) - { - DBG2(DBG_NET, "receiving from socket failed!"); - /* try again after a delay */ - sleep(1); - continue; - } - - /* parse message header */ - message = message_create_from_packet(packet); - if (message->parse_header(message) != SUCCESS) + DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " + "sending INVALID_MAJOR_VERSION", message->get_major_version(message), + message->get_minor_version(message), packet->get_source(packet)); + send_notify(message, INVALID_MAJOR_VERSION, chunk_empty); + message->destroy(message); + return JOB_REQUEUE_DIRECT; + } + + if (message->get_request(message) && + message->get_exchange_type(message) == IKE_SA_INIT) + { + /* check for cookies */ + if (cookie_required(this, message)) { - DBG1(DBG_NET, "received invalid IKE header from %H - ignored", - packet->get_source(packet)); + u_int32_t now = time(NULL); + chunk_t cookie = cookie_build(this, message, now - this->secret_offset, + chunk_from_thing(this->secret)); + + DBG2(DBG_NET, "received packet from: %#H to %#H", + message->get_source(message), + message->get_destination(message)); + DBG2(DBG_NET, "sending COOKIE notify to %H", + message->get_source(message)); + send_notify(message, COOKIE, cookie); + chunk_free(&cookie); + if (++this->secret_used > COOKIE_REUSE) + { + /* create new cookie */ + DBG1(DBG_NET, "generating new cookie secret after %d uses", + this->secret_used); + memcpy(this->secret_old, this->secret, SECRET_LENGTH); + this->randomizer->get_pseudo_random_bytes(this->randomizer, + SECRET_LENGTH, this->secret); + this->secret_switch = now; + this->secret_used = 0; + } message->destroy(message); - continue; + return JOB_REQUEUE_DIRECT; } - /* check IKE major version */ - if (message->get_major_version(message) != IKE_MAJOR_VERSION) + /* check if peer has not too many IKE_SAs half open */ + if (peer_to_aggressive(this, message)) { - DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " - "sending INVALID_MAJOR_VERSION", message->get_major_version(message), - message->get_minor_version(message), packet->get_source(packet)); - send_notify(message, INVALID_MAJOR_VERSION, chunk_empty); + DBG1(DBG_NET, "ignoring IKE_SA setup from %H, " + "peer to aggressive", message->get_source(message)); message->destroy(message); - continue; - } - - if (message->get_request(message) && - message->get_exchange_type(message) == IKE_SA_INIT) - { - /* check for cookies */ - if (cookie_required(this, message)) - { - u_int32_t now = time(NULL); - chunk_t cookie = cookie_build(this, message, now - this->secret_offset, - chunk_from_thing(this->secret)); - - DBG2(DBG_NET, "received packet from: %#H to %#H", - message->get_source(message), - message->get_destination(message)); - DBG2(DBG_NET, "sending COOKIE notify to %H", - message->get_source(message)); - send_notify(message, COOKIE, cookie); - chunk_free(&cookie); - if (++this->secret_used > COOKIE_REUSE) - { - /* create new cookie */ - DBG1(DBG_NET, "generating new cookie secret after %d uses", - this->secret_used); - memcpy(this->secret_old, this->secret, SECRET_LENGTH); - this->randomizer->get_pseudo_random_bytes(this->randomizer, - SECRET_LENGTH, this->secret); - this->secret_switch = now; - this->secret_used = 0; - } - message->destroy(message); - continue; - } - - /* check if peer has not too many IKE_SAs half open */ - if (peer_to_aggressive(this, message)) - { - DBG1(DBG_NET, "ignoring IKE_SA setup from %H, " - "peer to aggressive", message->get_source(message)); - message->destroy(message); - continue; - } + return JOB_REQUEUE_DIRECT; } - job = (job_t *)process_message_job_create(message); - charon->job_queue->add(charon->job_queue, job); } + job = (job_t*)process_message_job_create(message); + charon->processor->queue_job(charon->processor, job); + return JOB_REQUEUE_DIRECT; } /** @@ -340,8 +335,7 @@ static void receive_packets(private_receiver_t *this) */ static void destroy(private_receiver_t *this) { - pthread_cancel(this->assigned_thread); - pthread_join(this->assigned_thread, NULL); + this->job->cancel(this->job); this->randomizer->destroy(this->randomizer); this->hasher->destroy(this->hasher); free(this); @@ -366,12 +360,10 @@ receiver_t *receiver_create() this->secret); memcpy(this->secret_old, this->secret, SECRET_LENGTH); - if (pthread_create(&this->assigned_thread, NULL, - (void*)receive_packets, this) != 0) - { - free(this); - charon->kill(charon, "unable to create receiver thread"); - } + this->job = callback_job_create((callback_job_cb_t)receive_packets, + this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); return &this->public; } + diff --git a/src/charon/network/sender.c b/src/charon/network/sender.c index 933b8c192..f934dc509 100644 --- a/src/charon/network/sender.c +++ b/src/charon/network/sender.c @@ -28,6 +28,7 @@ #include <daemon.h> #include <network/socket.h> +#include <processing/jobs/callback_job.h> typedef struct private_sender_t private_sender_t; @@ -39,12 +40,12 @@ struct private_sender_t { /** * Public part of a sender_t object. */ - sender_t public; + sender_t public; - /** - * Assigned thread. - */ - pthread_t assigned_thread; + /** + * Sender threads job. + */ + callback_job_t *job; /** * The packets are stored in a linked list @@ -82,37 +83,29 @@ static void send_(private_sender_t *this, packet_t *packet) /** * Implementation of private_sender_t.send_packets. */ -static void send_packets(private_sender_t * this) +static job_requeue_t send_packets(private_sender_t * this) { - /* cancellation disabled by default */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - DBG1(DBG_NET, "sender thread running, thread_ID: %06u", (int)pthread_self()); + packet_t *packet; + int oldstate; - charon->drop_capabilities(charon, TRUE); - - while (TRUE) + pthread_mutex_lock(&this->mutex); + while (this->list->get_count(this->list) == 0) { - packet_t *packet; - int oldstate; - - pthread_mutex_lock(&this->mutex); - /* go to wait while no packets available */ - while (this->list->get_count(this->list) == 0) - { - /* add cleanup handler, wait for packet, remove cleanup handler */ - pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&this->mutex); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - pthread_cond_wait(&this->condvar, &this->mutex); - - pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - } - this->list->remove_first(this->list, (void**)&packet); - pthread_mutex_unlock(&this->mutex); + /* add cleanup handler, wait for packet, remove cleanup handler */ + pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&this->mutex); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + + pthread_cond_wait(&this->condvar, &this->mutex); - charon->socket->send(charon->socket, packet); - packet->destroy(packet); + pthread_setcancelstate(oldstate, NULL); + pthread_cleanup_pop(0); } + this->list->remove_first(this->list, (void**)&packet); + pthread_mutex_unlock(&this->mutex); + + charon->socket->send(charon->socket, packet); + packet->destroy(packet); + return JOB_REQUEUE_DIRECT; } /** @@ -125,8 +118,7 @@ static void destroy(private_sender_t *this) { sched_yield(); } - pthread_cancel(this->assigned_thread); - pthread_join(this->assigned_thread, NULL); + this->job->cancel(this->job); this->list->destroy(this->list); free(this); } @@ -145,11 +137,10 @@ sender_t * sender_create() pthread_mutex_init(&this->mutex, NULL); pthread_cond_init(&this->condvar, NULL); - if (pthread_create(&this->assigned_thread, NULL, - (void*)send_packets, this) != 0) - { - charon->kill(charon, "unable to create sender thread"); - } + this->job = callback_job_create((callback_job_cb_t)send_packets, + this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); - return &(this->public); + return &this->public; } + diff --git a/src/charon/processing/event_queue.c b/src/charon/processing/event_queue.c deleted file mode 100644 index 40bcb1ed8..000000000 --- a/src/charon/processing/event_queue.c +++ /dev/null @@ -1,290 +0,0 @@ -/** - * @file event_queue.c - * - * @brief Implementation of event_queue_t - * - */ - -/* - * 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 <stdlib.h> - -#include "event_queue.h" - -#include <library.h> -#include <utils/linked_list.h> - - - -typedef struct event_t event_t; - -/** - * Event containing a job and a schedule time - */ -struct event_t { - /** - * Time to fire the event. - */ - timeval_t time; - - /** - * Every event has its assigned job. - */ - job_t * job; -}; - -/** - * destroy an event and its job - */ -static void event_destroy(event_t *event) -{ - event->job->destroy(event->job); - free(event); -} - -typedef struct private_event_queue_t private_event_queue_t; - -/** - * Private Variables and Functions of event_queue_t class. - */ -struct private_event_queue_t { - /** - * Public part. - */ - event_queue_t public; - - /** - * The events are stored in a linked list of type linked_list_t. - */ - linked_list_t *list; - - /** - * Access to linked_list is locked through this mutex. - */ - pthread_mutex_t mutex; - - /** - * If the queue is empty or an event has not to be fired - * a thread has to wait. - * - * This condvar is used to wake up such a thread. - */ - pthread_cond_t condvar; -}; - -/** - * Returns the difference of to timeval structs in milliseconds - */ -static long time_difference(struct timeval *end_time, struct timeval *start_time) -{ - time_t s; - suseconds_t us; - - s = (end_time->tv_sec - start_time->tv_sec); - us = (end_time->tv_usec - start_time->tv_usec); - return ((s * 1000) + us/1000); -} - -/** - * Implements event_queue_t.get_count - */ -static int get_count(private_event_queue_t *this) -{ - int count; - pthread_mutex_lock(&(this->mutex)); - count = this->list->get_count(this->list); - pthread_mutex_unlock(&(this->mutex)); - return count; -} - -/** - * Implements event_queue_t.get - */ -static job_t *get(private_event_queue_t *this) -{ - timespec_t timeout; - timeval_t current_time; - event_t * next_event; - job_t *job; - int oldstate; - - pthread_mutex_lock(&(this->mutex)); - - while (TRUE) - { - while(this->list->get_count(this->list) == 0) - { - /* add mutex unlock handler for cancellation, enable cancellation */ - pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex)); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - - pthread_cond_wait( &(this->condvar), &(this->mutex)); - - /* reset cancellation, remove mutex-unlock handler (without executing) */ - pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - } - - this->list->get_first(this->list, (void **)&next_event); - - gettimeofday(¤t_time, NULL); - long difference = time_difference(¤t_time,&(next_event->time)); - if (difference <= 0) - { - timeout.tv_sec = next_event->time.tv_sec; - timeout.tv_nsec = next_event->time.tv_usec * 1000; - - /* add mutex unlock handler for cancellation, enable cancellation */ - pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex)); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - - pthread_cond_timedwait(&(this->condvar), &(this->mutex), &timeout); - - /* reset cancellation, remove mutex-unlock handler (without executing) */ - pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - } - else - { - /* event available */ - this->list->remove_first(this->list, (void **)&next_event); - job = next_event->job; - free(next_event); - break; - } - } - pthread_cond_signal( &(this->condvar)); - pthread_mutex_unlock(&(this->mutex)); - - return job; -} - -/** - * Implements function add_absolute of event_queue_t. - * See #event_queue_s.add_absolute for description. - */ -static void add_absolute(private_event_queue_t *this, job_t *job, timeval_t time) -{ - event_t *event; - event_t *current_event; - iterator_t *iterator; - - /* create event */ - event = malloc_thing(event_t); - event->time = time; - event->job = job; - - pthread_mutex_lock(&(this->mutex)); - - /* while just used to break out */ - while(TRUE) - { - if (this->list->get_count(this->list) == 0) - { - this->list->insert_first(this->list,event); - break; - } - - /* check last entry */ - this->list->get_last(this->list,(void **) ¤t_event); - - if (time_difference(&(event->time), &(current_event->time)) >= 0) - { - /* my event has to be fired after the last event in list */ - this->list->insert_last(this->list,event); - break; - } - - /* check first entry */ - this->list->get_first(this->list,(void **) ¤t_event); - - if (time_difference(&(event->time), &(current_event->time)) < 0) - { - /* my event has to be fired before the first event in list */ - this->list->insert_first(this->list,event); - break; - } - - iterator = this->list->create_iterator(this->list,TRUE); - iterator->iterate(iterator, (void**)¤t_event); - /* first element has not to be checked (already done) */ - while(iterator->iterate(iterator, (void**)¤t_event)) - { - if (time_difference(&(event->time), &(current_event->time)) <= 0) - { - /* my event has to be fired before the current event in list */ - iterator->insert_before(iterator,event); - break; - } - } - iterator->destroy(iterator); - break; - } - - pthread_cond_signal( &(this->condvar)); - pthread_mutex_unlock(&(this->mutex)); -} - -/** - * Implements event_queue_t.add_relative. - */ -static void add_relative(event_queue_t *this, job_t *job, u_int32_t ms) -{ - timeval_t current_time; - timeval_t time; - - time_t s = ms / 1000; - suseconds_t us = (ms - s * 1000) * 1000; - - gettimeofday(¤t_time, NULL); - - time.tv_usec = (current_time.tv_usec + us) % 1000000; - time.tv_sec = current_time.tv_sec + (current_time.tv_usec + us)/1000000 + s; - - this->add_absolute(this, job, time); -} - - -/** - * Implements event_queue_t.destroy. - */ -static void event_queue_destroy(private_event_queue_t *this) -{ - this->list->destroy_function(this->list, (void*)event_destroy); - free(this); -} - -/* - * Documented in header - */ -event_queue_t *event_queue_create() -{ - private_event_queue_t *this = malloc_thing(private_event_queue_t); - - this->public.get_count = (int (*) (event_queue_t *event_queue)) get_count; - this->public.get = (job_t *(*) (event_queue_t *event_queue)) get; - this->public.add_absolute = (void (*) (event_queue_t *event_queue, job_t *job, timeval_t time)) add_absolute; - this->public.add_relative = (void (*) (event_queue_t *event_queue, job_t *job, u_int32_t ms)) add_relative; - this->public.destroy = (void (*) (event_queue_t *event_queue)) event_queue_destroy; - - this->list = linked_list_create(); - pthread_mutex_init(&(this->mutex), NULL); - pthread_cond_init(&(this->condvar), NULL); - - return (&this->public); -} diff --git a/src/charon/processing/event_queue.h b/src/charon/processing/event_queue.h deleted file mode 100644 index c85286bf2..000000000 --- a/src/charon/processing/event_queue.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * @file event_queue.h - * - * @brief Interface of job_queue_t. - * - */ - -/* - * 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. - */ - -#ifndef EVENT_QUEUE_H_ -#define EVENT_QUEUE_H_ - -typedef struct event_queue_t event_queue_t; - -#include <sys/time.h> - -#include <library.h> -#include <processing/jobs/job.h> - -/** - * @brief Event-Queue used to store timed events. - * - * Added events are sorted. The get method blocks until - * the time is elapsed to process the next event. The get - * method is called from the scheduler_t thread, which - * will add the jobs to to job_queue_t for further processing. - * - * Although the event-queue is based on a linked_list_t - * all access functions are thread-save implemented. - * - * @b Constructors: - * - event_queue_create() - * - * @ingroup processing - */ -struct event_queue_t { - - /** - * @brief Returns number of events in queue. - * - * @param event_queue calling object - * @return number of events in queue - */ - int (*get_count) (event_queue_t *event_queue); - - /** - * @brief Get the next job from the event-queue. - * - * If no event is pending, this function blocks until a job can be returned. - * - * @param event_queue calling object - * @param[out] job pointer to a job pointer where to job is returned to - * @return next job - */ - job_t *(*get) (event_queue_t *event_queue); - - /** - * @brief Adds a event to the queue, using a relative time. - * - * This function is non blocking and adds a job_t at a specific time to the list. - * The specific job object has to get destroyed by the thread which - * removes the job. - * - * @param event_queue calling object - * @param[in] job job to add to the queue (job is not copied) - * @param[in] time relative time, when the event has to get fired - */ - void (*add_relative) (event_queue_t *event_queue, job_t *job, u_int32_t ms); - - /** - * @brief Adds a event to the queue, using an absolute time. - * - * This function is non blocking and adds a job_t at a specific time to the list. - * The specific job object has to get destroyed by the thread which - * removes the job. - * - * @param event_queue calling object - * @param[in] job job to add to the queue (job is not copied) - * @param[in] time absolute time, when the event has to get fired - */ - void (*add_absolute) (event_queue_t *event_queue, job_t *job, timeval_t time); - - /** - * @brief Destroys a event_queue object. - * - * @warning The caller of this function has to make sure - * that no thread is going to add or get an event from the event_queue - * after calling this function. - * - * @param event_queue calling object - */ - void (*destroy) (event_queue_t *event_queue); -}; - -/** - * @brief Creates an empty event_queue. - * - * @returns event_queue_t object - * - * @ingroup processing - */ -event_queue_t *event_queue_create(void); - -#endif /*EVENT_QUEUE_H_*/ diff --git a/src/charon/processing/job_queue.c b/src/charon/processing/job_queue.c deleted file mode 100644 index 2310ca6ff..000000000 --- a/src/charon/processing/job_queue.c +++ /dev/null @@ -1,139 +0,0 @@ -/** - * @file job_queue.c - * - * @brief Implementation of job_queue_t - * - */ - -/* - * 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 <stdlib.h> -#include <pthread.h> - -#include "job_queue.h" - -#include <utils/linked_list.h> - - -typedef struct private_job_queue_t private_job_queue_t; - -/** - * @brief Private Variables and Functions of job_queue class - * - */ -struct private_job_queue_t { - - /** - * public members - */ - job_queue_t public; - - /** - * The jobs are stored in a linked list - */ - linked_list_t *list; - - /** - * access to linked_list is locked through this mutex - */ - pthread_mutex_t mutex; - - /** - * If the queue is empty a thread has to wait - * This condvar is used to wake up such a thread - */ - pthread_cond_t condvar; -}; - - -/** - * implements job_queue_t.get_count - */ -static int get_count(private_job_queue_t *this) -{ - int count; - pthread_mutex_lock(&(this->mutex)); - count = this->list->get_count(this->list); - pthread_mutex_unlock(&(this->mutex)); - return count; -} - -/** - * implements job_queue_t.get - */ -static job_t *get(private_job_queue_t *this) -{ - int oldstate; - job_t *job; - pthread_mutex_lock(&(this->mutex)); - /* go to wait while no jobs available */ - while(this->list->get_count(this->list) == 0) - { - /* add mutex unlock handler for cancellation, enable cancellation */ - pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex)); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - - pthread_cond_wait( &(this->condvar), &(this->mutex)); - - /* reset cancellation, remove mutex-unlock handler (without executing) */ - pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - } - this->list->remove_first(this->list, (void **)&job); - pthread_mutex_unlock(&(this->mutex)); - return job; -} - -/** - * implements function job_queue_t.add - */ -static void add(private_job_queue_t *this, job_t *job) -{ - pthread_mutex_lock(&(this->mutex)); - this->list->insert_last(this->list,job); - pthread_cond_signal( &(this->condvar)); - pthread_mutex_unlock(&(this->mutex)); -} - -/** - * implements job_queue_t.destroy - */ -static void job_queue_destroy (private_job_queue_t *this) -{ - this->list->destroy_offset(this->list, offsetof(job_t, destroy)); - free(this); -} - -/* - * - * Documented in header - */ -job_queue_t *job_queue_create(void) -{ - private_job_queue_t *this = malloc_thing(private_job_queue_t); - - this->public.get_count = (int(*)(job_queue_t*))get_count; - this->public.get = (job_t*(*)(job_queue_t*))get; - this->public.add = (void(*)(job_queue_t*, job_t*))add; - this->public.destroy = (void(*)(job_queue_t*))job_queue_destroy; - - this->list = linked_list_create(); - pthread_mutex_init(&(this->mutex), NULL); - pthread_cond_init(&(this->condvar), NULL); - - return (&this->public); -} diff --git a/src/charon/processing/job_queue.h b/src/charon/processing/job_queue.h deleted file mode 100644 index 9b58588ae..000000000 --- a/src/charon/processing/job_queue.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file job_queue.h - * - * @brief Interface of job_queue_t. - * - */ - -/* - * 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. - */ - -#ifndef JOB_QUEUE_H_ -#define JOB_QUEUE_H_ - -typedef struct job_queue_t job_queue_t; - -#include <library.h> -#include <processing/jobs/job.h> - -/** - * @brief The job queue stores jobs, which will be processed by the thread_pool_t. - * - * Jobs are added from various sources, from the threads and - * from the event_queue_t. - * Although the job-queue is based on a linked_list_t - * all access functions are thread-save implemented. - * - * @b Constructors: - * - job_queue_create() - * - * @ingroup processing - */ -struct job_queue_t { - - /** - * @brief Returns number of jobs in queue. - * - * @param job_queue_t calling object - * @returns number of items in queue - */ - int (*get_count) (job_queue_t *job_queue); - - /** - * @brief Get the next job from the queue. - * - * If the queue is empty, this function blocks until a job can be returned. - * After using, the returned job has to get destroyed by the caller. - * - * @param job_queue_t calling object - * @param[out] job pointer to a job pointer where to job is returned to - * @return next job - */ - job_t *(*get) (job_queue_t *job_queue); - - /** - * @brief Adds a job to the queue. - * - * This function is non blocking and adds a job_t to the list. - * The specific job object has to get destroyed by the thread which - * removes the job. - * - * @param job_queue_t calling object - * @param job job to add to the queue (job is not copied) - */ - void (*add) (job_queue_t *job_queue, job_t *job); - - /** - * @brief Destroys a job_queue object. - * - * @warning The caller of this function has to make sure - * that no thread is going to add or get a job from the job_queue - * after calling this function. - * - * @param job_queue_t calling object - */ - void (*destroy) (job_queue_t *job_queue); -}; - -/** - * @brief Creates an empty job_queue. - * - * @return job_queue_t object - * - * @ingroup processing - */ -job_queue_t *job_queue_create(void); - -#endif /*JOB_QUEUE_H_*/ diff --git a/src/charon/processing/jobs/acquire_job.c b/src/charon/processing/jobs/acquire_job.c index b4ffb258d..48a77f558 100644 --- a/src/charon/processing/jobs/acquire_job.c +++ b/src/charon/processing/jobs/acquire_job.c @@ -43,17 +43,17 @@ struct private_acquire_job_t { }; /** - * Implementation of job_t.get_type. + * Implementation of job_t.destroy. */ -static job_type_t get_type(private_acquire_job_t *this) +static void destroy(private_acquire_job_t *this) { - return ACQUIRE; + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_acquire_job_t *this) +static void execute(private_acquire_job_t *this) { ike_sa_t *ike_sa; @@ -63,20 +63,14 @@ static status_t execute(private_acquire_job_t *this) { DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for acquiring", this->reqid); - return DESTROY_ME; } - ike_sa->acquire(ike_sa, this->reqid); - - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return DESTROY_ME; -} - -/** - * Implementation of job_t.destroy. - */ -static void destroy(private_acquire_job_t *this) -{ - free(this); + else + { + ike_sa->acquire(ike_sa, this->reqid); + + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + destroy(this); } /* @@ -87,12 +81,11 @@ acquire_job_t *acquire_job_create(u_int32_t reqid) private_acquire_job_t *this = malloc_thing(private_acquire_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.execute = (void (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*)(job_t*)) destroy; /* private variables */ this->reqid = reqid; - return &(this->public); + return &this->public; } diff --git a/src/charon/processing/jobs/callback_job.c b/src/charon/processing/jobs/callback_job.c new file mode 100644 index 000000000..53e7caa95 --- /dev/null +++ b/src/charon/processing/jobs/callback_job.c @@ -0,0 +1,213 @@ +/** + * @file callback_job.c + * + * @brief Implementation of callback_job_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 "callback_job.h" + +#include <daemon.h> + +typedef struct private_callback_job_t private_callback_job_t; + +/** + * Private data of an callback_job_t Object. + */ +struct private_callback_job_t { + /** + * Public callback_job_t interface. + */ + callback_job_t public; + + /** + * Callback to call on execution + */ + callback_job_cb_t callback; + + /** + * parameter to supply to callback + */ + void *data; + + /** + * cleanup function for data + */ + callback_job_cleanup_t cleanup; + + /** + * thread ID of the job, if running + */ + pthread_t thread; + + /** + * mutex to access jobs interna + */ + pthread_mutex_t mutex; + + /** + * condvar to synchronize thread startup/cancellation + */ + pthread_cond_t condvar; + + /** + * list of asociated child jobs + */ + linked_list_t *children; + + /** + * parent of this job, or NULL + */ + private_callback_job_t *parent; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_callback_job_t *this) +{ + if (this->cleanup) + { + this->cleanup(this->data); + } + this->children->destroy(this->children); + free(this); +} + +/** + * unregister a child from its parent, if any. + */ +static void unregister(private_callback_job_t *this) +{ + if (this->parent) + { + iterator_t *iterator; + private_callback_job_t *child; + + pthread_mutex_lock(&this->parent->mutex); + iterator = this->parent->children->create_iterator(this->parent->children, TRUE); + while (iterator->iterate(iterator, (void**)&child)) + { + if (child == this) + { + iterator->remove(iterator); + break; + } + } + iterator->destroy(iterator); + pthread_mutex_unlock(&this->parent->mutex); + } +} + +/** + * Implementation of callback_job_t.cancel. + */ +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 */ + this->children->invoke(this->children, offsetof(callback_job_t, cancel)); + pthread_mutex_unlock(&this->mutex); + + /* terminate thread */ + pthread_cancel(thread); + pthread_join(thread, NULL); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_callback_job_t *this) +{ + bool cleanup = FALSE; + + pthread_mutex_lock(&this->mutex); + this->thread = pthread_self(); + pthread_cond_signal(&this->condvar); + pthread_mutex_unlock(&this->mutex); + + pthread_cleanup_push((void*)destroy, this); + while (TRUE) + { + switch (this->callback(this->data)) + { + case JOB_REQUEUE_DIRECT: + continue; + case JOB_REQUEUE_FAIR: + { + charon->processor->queue_job(charon->processor, + &this->public.job_interface); + break; + } + case JOB_REQUEUE_NONE: + default: + { + cleanup = TRUE; + break; + } + } + break; + } + unregister(this); + pthread_cleanup_pop(cleanup); +} + +/* + * Described in header. + */ +callback_job_t *callback_job_create(callback_job_cb_t cb, void *data, + callback_job_cleanup_t cleanup, + callback_job_t *parent) +{ + private_callback_job_t *this = malloc_thing(private_callback_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + this->public.cancel = (void(*)(callback_job_t*))cancel; + + /* private variables */ + pthread_mutex_init(&this->mutex, NULL); + pthread_cond_init(&this->condvar, NULL); + this->callback = cb; + this->data = data; + this->cleanup = cleanup; + this->thread = 0; + this->children = linked_list_create(); + this->parent = (private_callback_job_t*)parent; + + /* register us at parent */ + if (parent) + { + pthread_mutex_lock(&this->parent->mutex); + this->parent->children->insert_last(this->parent->children, this); + pthread_mutex_unlock(&this->parent->mutex); + } + + return &this->public; +} + diff --git a/src/charon/processing/jobs/callback_job.h b/src/charon/processing/jobs/callback_job.h new file mode 100644 index 000000000..169f2d207 --- /dev/null +++ b/src/charon/processing/jobs/callback_job.h @@ -0,0 +1,135 @@ +/** + * @file callback_job.h + * + * @brief Interface of callback_job_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 CALLBACK_JOB_H_ +#define CALLBACK_JOB_H_ + +typedef struct callback_job_t callback_job_t; + +#include <library.h> +#include <processing/jobs/job.h> + + +typedef enum job_requeue_t job_requeue_t; + +/** + * @brief Job requeueing policy + * + * The job requeueing policy defines how a job is handled when the callback + * function returns. + * + * @ingroup jobs + */ +enum job_requeue_t { + + /** + * Do not requeue job, destroy it + */ + JOB_REQUEUE_NONE, + + /** + * Reque the job fairly, meaning it has to requeue as any other job + */ + JOB_REQUEUE_FAIR, + + /** + * Reexecute the job directly, without the need of requeueing it + */ + JOB_REQUEUE_DIRECT, +}; + +/** + * @brief The callback function to use for the callback job. + * + * This is the function to use as callback for a callback job. It receives + * a parameter supplied to the callback jobs constructor. + * + * @param data param supplied to job + * @return requeing policy how to requeue the job + * + * @ingroup jobs + */ +typedef job_requeue_t (*callback_job_cb_t)(void *data); + +/** + * @brief Cleanup function to use for data cleanup. + * + * The callback has an optional user argument which receives data. However, + * this data may be cleaned up if it is allocated. This is the function + * to supply to the constructor. + * + * @param data param supplied to job + * @return requeing policy how to requeue the job + * + * @ingroup jobs + */ +typedef void (*callback_job_cleanup_t)(void *data); + +/** + * @brief Class representing an callback Job. + * + * This is a special job which allows a simple callback function to + * be executed by a thread of the thread pool. This allows simple execution + * of asynchronous methods, without to manage threads. + * + * @b Constructors: + * - callback_job_create() + * + * @ingroup jobs + */ +struct callback_job_t { + /** + * The job_t interface. + */ + job_t job_interface; + + /** + * @brief Cancel the jobs thread and wait for its termination. + * + * @param this calling object + */ + void (*cancel)(callback_job_t *this); +}; + +/** + * @brief Creates a callback job. + * + * The cleanup function is called when the job gets destroyed to destroy + * the associated data. + * If parent is not NULL, the specified job gets an association. Whenever + * the parent gets cancelled (or runs out), all of its children are cancelled, + * too. + * + * @param cb callback to call from the processor + * @param data user data to supply to callback + * @param cleanup destructor for data on destruction, or NULL + * @param parent parent of this job + * @return callback_job_t object + * + * @ingroup jobs + */ +callback_job_t *callback_job_create(callback_job_cb_t cb, void *data, + callback_job_cleanup_t cleanup, + callback_job_t *parent); + +#endif /* CALLBACK_JOB_H_ */ + diff --git a/src/charon/processing/jobs/delete_child_sa_job.c b/src/charon/processing/jobs/delete_child_sa_job.c index f694696b0..23f330293 100644 --- a/src/charon/processing/jobs/delete_child_sa_job.c +++ b/src/charon/processing/jobs/delete_child_sa_job.c @@ -54,17 +54,17 @@ struct private_delete_child_sa_job_t { }; /** - * Implementation of job_t.get_type. + * Implementation of job_t.destroy. */ -static job_type_t get_type(private_delete_child_sa_job_t *this) +static void destroy(private_delete_child_sa_job_t *this) { - return DELETE_CHILD_SA; + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_delete_child_sa_job_t *this) +static void execute(private_delete_child_sa_job_t *this) { ike_sa_t *ike_sa; @@ -74,20 +74,14 @@ static status_t execute(private_delete_child_sa_job_t *this) { DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for delete", this->reqid); - return DESTROY_ME; } - ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi); - - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return DESTROY_ME; -} - -/** - * Implementation of job_t.destroy. - */ -static void destroy(private_delete_child_sa_job_t *this) -{ - free(this); + else + { + ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi); + + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + destroy(this); } /* @@ -100,8 +94,7 @@ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, private_delete_child_sa_job_t *this = malloc_thing(private_delete_child_sa_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.execute = (void (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*)(job_t*)) destroy; /* private variables */ @@ -109,5 +102,6 @@ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, this->protocol = protocol; this->spi = spi; - return &(this->public); + return &this->public; } + diff --git a/src/charon/processing/jobs/delete_ike_sa_job.c b/src/charon/processing/jobs/delete_ike_sa_job.c index 706155aa6..8d8c0cf36 100644 --- a/src/charon/processing/jobs/delete_ike_sa_job.c +++ b/src/charon/processing/jobs/delete_ike_sa_job.c @@ -47,18 +47,20 @@ struct private_delete_ike_sa_job_t { bool delete_if_established; }; + /** - * Implements job_t.get_type. + * Implements job_t.destroy. */ -static job_type_t get_type(private_delete_ike_sa_job_t *this) +static void destroy(private_delete_ike_sa_job_t *this) { - return DELETE_IKE_SA; + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_delete_ike_sa_job_t *this) +static void execute(private_delete_ike_sa_job_t *this) { ike_sa_t *ike_sa; @@ -93,16 +95,7 @@ static status_t execute(private_delete_ike_sa_job_t *this) } } } - return DESTROY_ME; -} - -/** - * Implements job_t.destroy. - */ -static void destroy(private_delete_ike_sa_job_t *this) -{ - this->ike_sa_id->destroy(this->ike_sa_id); - free(this); + destroy(this); } /* @@ -114,8 +107,7 @@ delete_ike_sa_job_t *delete_ike_sa_job_create(ike_sa_id_t *ike_sa_id, private_delete_ike_sa_job_t *this = malloc_thing(private_delete_ike_sa_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.execute = (void (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*)(job_t *)) destroy;; /* private variables */ diff --git a/src/charon/processing/jobs/job.c b/src/charon/processing/jobs/job.c deleted file mode 100644 index d32d1bc61..000000000 --- a/src/charon/processing/jobs/job.c +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file job.c - * - * @brief Interface additions to job_t. - * - */ - -/* - * 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 "job.h" - -ENUM(job_type_names, PROCESS_MESSAGE, SEND_DPD, - "PROCESS_MESSAGE", - "RETRANSMIT", - "INITIATE", - "ROUTE", - "ACQUIRE", - "DELETE_IKE_SA", - "DELETE_CHILD_SA", - "REKEY_CHILD_SA", - "REKEY_IKE_SA", - "SEND_KEEPALIVE", - "SEND_DPD", -); diff --git a/src/charon/processing/jobs/job.h b/src/charon/processing/jobs/job.h index 28632672d..1826c53b4 100644 --- a/src/charon/processing/jobs/job.h +++ b/src/charon/processing/jobs/job.h @@ -24,108 +24,14 @@ #ifndef JOB_H_ #define JOB_H_ -typedef enum job_type_t job_type_t; typedef struct job_t job_t; #include <library.h> -/** - * @brief Definition of the various job types. - * - * @ingroup jobs - */ -enum job_type_t { - /** - * Process an incoming IKEv2-Message. - * - * Job is implemented in class process_message_job_t - */ - PROCESS_MESSAGE, - - /** - * Retransmit an IKEv2-Message. - * - * Job is implemented in class retransmit_job_t - */ - RETRANSMIT, - - /** - * Set up a CHILD_SA, optional with an IKE_SA. - * - * Job is implemented in class initiate_job_t - */ - INITIATE, - - /** - * Install SPD entries. - * - * Job is implemented in class route_job_t - */ - ROUTE, - - /** - * React on a acquire message from the kernel (e.g. setup CHILD_SA) - * - * Job is implemented in class acquire_job_t - */ - ACQUIRE, - - /** - * Delete an IKE_SA. - * - * Job is implemented in class delete_ike_sa_job_t - */ - DELETE_IKE_SA, - - /** - * Delete a CHILD_SA. - * - * Job is implemented in class delete_child_sa_job_t - */ - DELETE_CHILD_SA, - - /** - * Rekey a CHILD_SA. - * - * Job is implemented in class rekey_child_sa_job_t - */ - REKEY_CHILD_SA, - - /** - * Rekey an IKE_SA. - * - * Job is implemented in class rekey_ike_sa_job_t - */ - REKEY_IKE_SA, - - /** - * Send a keepalive packet. - * - * Job is implemented in class type send_keepalive_job_t - */ - SEND_KEEPALIVE, - - /** - * Send a DPD packet. - * - * Job is implemented in class type send_dpd_job_t - */ - SEND_DPD -}; - -/** - * enum name for job_type_t - * - * @ingroup jobs - */ -extern enum_name_t *job_type_names; - /** * @brief Job-Interface as it is stored in the job queue. * - * A job consists of a job-type and one or more assigned values. - * * @b Constructors: * - None, use specific implementation of the interface. * @@ -134,32 +40,26 @@ extern enum_name_t *job_type_names; struct job_t { /** - * @brief get type of job. - * - * @param this calling object - * @return type of this job - */ - job_type_t (*get_type) (job_t *this); - - /** * @brief Execute a job. * - * Call the internall job routine to process the - * job. If this method returns DESTROY_ME, the job - * must be destroyed by the caller. + * The processing facility executes a job using this method. Jobs are + * one-shot, they destroy themself after execution, so don't use a job + * once it has been executed. * * @param this calling object - * @return status of job execution */ - status_t (*execute) (job_t *this); + void (*execute) (job_t *this); /** - * @brief Destroys a job_t object + * @brief Destroy a job. + * + * Is only called whenever a job was not executed (e.g. due daemon shutdown). + * After execution, jobs destroy themself. * * @param job_t calling object */ void (*destroy) (job_t *job); }; - #endif /* JOB_H_ */ + diff --git a/src/charon/processing/jobs/process_message_job.c b/src/charon/processing/jobs/process_message_job.c index ee7484bbd..6a0921248 100644 --- a/src/charon/processing/jobs/process_message_job.c +++ b/src/charon/processing/jobs/process_message_job.c @@ -44,17 +44,18 @@ struct private_process_message_job_t { }; /** - * Implements job_t.get_type. + * Implements job_t.destroy. */ -static job_type_t get_type(private_process_message_job_t *this) +static void destroy(private_process_message_job_t *this) { - return PROCESS_MESSAGE; + this->message->destroy(this->message); + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_process_message_job_t *this) +static void execute(private_process_message_job_t *this) { ike_sa_t *ike_sa; @@ -75,16 +76,7 @@ static status_t execute(private_process_message_job_t *this) charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } } - return DESTROY_ME; -} - -/** - * Implements job_t.destroy. - */ -static void destroy(private_process_message_job_t *this) -{ - this->message->destroy(this->message); - free(this); + destroy(this); } /* @@ -95,8 +87,7 @@ process_message_job_t *process_message_job_create(message_t *message) private_process_message_job_t *this = malloc_thing(private_process_message_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.execute = (void (*) (job_t *)) execute; this->public.job_interface.destroy = (void(*)(job_t*))destroy; /* private variables */ diff --git a/src/charon/processing/jobs/rekey_child_sa_job.c b/src/charon/processing/jobs/rekey_child_sa_job.c index 3422b614d..f754e5a1f 100644 --- a/src/charon/processing/jobs/rekey_child_sa_job.c +++ b/src/charon/processing/jobs/rekey_child_sa_job.c @@ -53,17 +53,17 @@ struct private_rekey_child_sa_job_t { }; /** - * Implementation of job_t.get_type. + * Implementation of job_t.destroy. */ -static job_type_t get_type(private_rekey_child_sa_job_t *this) +static void destroy(private_rekey_child_sa_job_t *this) { - return REKEY_CHILD_SA; + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_rekey_child_sa_job_t *this) +static void execute(private_rekey_child_sa_job_t *this) { ike_sa_t *ike_sa; @@ -73,20 +73,13 @@ static status_t execute(private_rekey_child_sa_job_t *this) { DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for rekeying", this->reqid); - return DESTROY_ME; } - ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi); - - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return DESTROY_ME; -} - -/** - * Implementation of job_t.destroy. - */ -static void destroy(private_rekey_child_sa_job_t *this) -{ - free(this); + else + { + ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + destroy(this); } /* @@ -99,8 +92,7 @@ rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, private_rekey_child_sa_job_t *this = malloc_thing(private_rekey_child_sa_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.execute = (void (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*)(job_t*)) destroy; /* private variables */ @@ -108,5 +100,5 @@ rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, this->protocol = protocol; this->spi = spi; - return &(this->public); + return &this->public; } diff --git a/src/charon/processing/jobs/rekey_ike_sa_job.c b/src/charon/processing/jobs/rekey_ike_sa_job.c index f6c058634..020c3cce8 100644 --- a/src/charon/processing/jobs/rekey_ike_sa_job.c +++ b/src/charon/processing/jobs/rekey_ike_sa_job.c @@ -48,17 +48,18 @@ struct private_rekey_ike_sa_job_t { }; /** - * Implementation of job_t.get_type. + * Implementation of job_t.destroy. */ -static job_type_t get_type(private_rekey_ike_sa_job_t *this) +static void destroy(private_rekey_ike_sa_job_t *this) { - return REKEY_IKE_SA; + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_rekey_ike_sa_job_t *this) +static void execute(private_rekey_ike_sa_job_t *this) { ike_sa_t *ike_sa; status_t status = SUCCESS; @@ -68,36 +69,28 @@ static status_t execute(private_rekey_ike_sa_job_t *this) if (ike_sa == NULL) { DBG2(DBG_JOB, "IKE_SA to rekey not found"); - return DESTROY_ME; - } - - if (this->reauth) - { - ike_sa->reestablish(ike_sa); } else { - status = ike_sa->rekey(ike_sa); - } - - if (status == DESTROY_ME) - { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - } - else - { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + if (this->reauth) + { + status = ike_sa->reestablish(ike_sa); + } + else + { + status = ike_sa->rekey(ike_sa); + } + + if (status == DESTROY_ME) + { + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } } - return DESTROY_ME; -} - -/** - * Implementation of job_t.destroy. - */ -static void destroy(private_rekey_ike_sa_job_t *this) -{ - this->ike_sa_id->destroy(this->ike_sa_id); - free(this); + destroy(this); } /* @@ -108,8 +101,7 @@ rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth) private_rekey_ike_sa_job_t *this = malloc_thing(private_rekey_ike_sa_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.execute = (void (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*)(job_t*)) destroy; /* private variables */ diff --git a/src/charon/processing/jobs/retransmit_job.c b/src/charon/processing/jobs/retransmit_job.c index 5bfa20dfd..8c15aa651 100644 --- a/src/charon/processing/jobs/retransmit_job.c +++ b/src/charon/processing/jobs/retransmit_job.c @@ -48,17 +48,18 @@ struct private_retransmit_job_t { }; /** - * Implements job_t.get_type. + * Implements job_t.destroy. */ -static job_type_t get_type(private_retransmit_job_t *this) +static void destroy(private_retransmit_job_t *this) { - return RETRANSMIT; + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_retransmit_job_t *this) +static void execute(private_retransmit_job_t *this) { ike_sa_t *ike_sa; @@ -77,16 +78,7 @@ static status_t execute(private_retransmit_job_t *this) charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } } - return DESTROY_ME; -} - -/** - * Implements job_t.destroy. - */ -static void destroy(private_retransmit_job_t *this) -{ - this->ike_sa_id->destroy(this->ike_sa_id); - free(this); + destroy(this); } /* @@ -97,8 +89,7 @@ retransmit_job_t *retransmit_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa private_retransmit_job_t *this = malloc_thing(private_retransmit_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.execute = (void (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*) (job_t *)) destroy; /* private variables */ diff --git a/src/charon/processing/jobs/roam_job.c b/src/charon/processing/jobs/roam_job.c new file mode 100644 index 000000000..3b5cd0ed2 --- /dev/null +++ b/src/charon/processing/jobs/roam_job.c @@ -0,0 +1,115 @@ +/** + * @file roam_job.c + * + * @brief Implementation of roam_job_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 <stdlib.h> + +#include "roam_job.h" + +#include <sa/ike_sa.h> +#include <daemon.h> + + +typedef struct private_roam_job_t private_roam_job_t; + +/** + * Private data of an roam_job_t Object + */ +struct private_roam_job_t { + /** + * public roam_job_t interface + */ + roam_job_t public; + + /** + * has the address list changed, or the routing only? + */ + bool address; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_roam_job_t *this) +{ + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_roam_job_t *this) +{ + ike_sa_t *ike_sa; + linked_list_t *list; + ike_sa_id_t *id; + iterator_t *iterator; + + /* iterating over all IKE_SAs gives us no way to checkin_and_destroy + * after a DESTROY_ME, so we check out each available IKE_SA by hand. */ + list = linked_list_create(); + iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager); + while (iterator->iterate(iterator, (void**)&ike_sa)) + { + id = ike_sa->get_id(ike_sa); + list->insert_last(list, id->clone(id)); + } + iterator->destroy(iterator); + + while (list->remove_last(list, (void**)&id) == SUCCESS) + { + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id); + if (ike_sa) + { + if (ike_sa->roam(ike_sa, this->address) == DESTROY_ME) + { + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + } + id->destroy(id); + } + list->destroy(list); + + destroy(this); +} + +/* + * Described in header + */ +roam_job_t *roam_job_create(bool address) +{ + private_roam_job_t *this = malloc_thing(private_roam_job_t); + + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + + this->address = address; + + return &this->public; +} + diff --git a/src/charon/processing/jobs/roam_job.h b/src/charon/processing/jobs/roam_job.h new file mode 100644 index 000000000..293b09f08 --- /dev/null +++ b/src/charon/processing/jobs/roam_job.h @@ -0,0 +1,61 @@ +/** + * @file roam_job.h + * + * @brief Interface of roam_job_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 ROAM_JOB_H_ +#define ROAM_JOB_H_ + +typedef struct roam_job_t roam_job_t; + +#include <library.h> +#include <sa/ike_sa_id.h> +#include <processing/jobs/job.h> + +/** + * @brief A job to inform IKE_SAs about changed local address setup. + * + * If a local address appears or disappears, the kernel fires this job to + * update all IKE_SAs. + * + * @b Constructors: + * - roam_job_create() + * + * @ingroup jobs + */ +struct roam_job_t { + + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * @brief Creates a job to inform IKE_SAs about an updated address list. + * + * @param address TRUE if address list changed, FALSE if routing changed + * @return initiate_ike_sa_job_t object + * + * @ingroup jobs + */ +roam_job_t *roam_job_create(bool address); + +#endif /*ROAM_JOB_H_*/ + diff --git a/src/charon/processing/jobs/send_dpd_job.c b/src/charon/processing/jobs/send_dpd_job.c index 7294d78d5..f6786bfb4 100644 --- a/src/charon/processing/jobs/send_dpd_job.c +++ b/src/charon/processing/jobs/send_dpd_job.c @@ -47,45 +47,35 @@ struct private_send_dpd_job_t { }; /** - * Implements send_dpd_job_t.get_type. + * Implements job_t.destroy. */ -static job_type_t get_type(private_send_dpd_job_t *this) +static void destroy(private_send_dpd_job_t *this) { - return SEND_DPD; + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_send_dpd_job_t *this) +static void execute(private_send_dpd_job_t *this) { ike_sa_t *ike_sa; ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id); - if (ike_sa == NULL) - { - return DESTROY_ME; - } - - if (ike_sa->send_dpd(ike_sa) == DESTROY_ME) + if (ike_sa) { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + if (ike_sa->send_dpd(ike_sa) == DESTROY_ME) + { + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } } - else - { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - } - return DESTROY_ME; -} - -/** - * Implements job_t.destroy. - */ -static void destroy(private_send_dpd_job_t *this) -{ - this->ike_sa_id->destroy(this->ike_sa_id); - free(this); + destroy(this); } /* @@ -96,15 +86,12 @@ send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id) private_send_dpd_job_t *this = malloc_thing(private_send_dpd_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; this->public.job_interface.destroy = (void (*) (job_t *)) destroy; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; - - /* public functions */ - this->public.destroy = (void (*)(send_dpd_job_t *)) destroy; + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; /* private variables */ this->ike_sa_id = ike_sa_id->clone(ike_sa_id); - return &(this->public); + return &this->public; } diff --git a/src/charon/processing/jobs/send_dpd_job.h b/src/charon/processing/jobs/send_dpd_job.h index 26c9e2e81..0e4059131 100644 --- a/src/charon/processing/jobs/send_dpd_job.h +++ b/src/charon/processing/jobs/send_dpd_job.h @@ -45,13 +45,6 @@ struct send_dpd_job_t { * implements job_t interface */ job_t job_interface; - - /** - * @brief Destroys an send_dpd_job_t object. - * - * @param this send_dpd_job_t object to destroy - */ - void (*destroy) (send_dpd_job_t *this); }; /** diff --git a/src/charon/processing/jobs/send_keepalive_job.c b/src/charon/processing/jobs/send_keepalive_job.c index 1c1cb288e..8cb51e5dd 100644 --- a/src/charon/processing/jobs/send_keepalive_job.c +++ b/src/charon/processing/jobs/send_keepalive_job.c @@ -47,38 +47,29 @@ struct private_send_keepalive_job_t { }; /** - * Implements send_keepalive_job_t.get_type. + * Implements job_t.destroy. */ -static job_type_t get_type(private_send_keepalive_job_t *this) +static void destroy(private_send_keepalive_job_t *this) { - return SEND_KEEPALIVE; + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); } /** * Implementation of job_t.execute. */ -static status_t execute(private_send_keepalive_job_t *this) +static void execute(private_send_keepalive_job_t *this) { ike_sa_t *ike_sa; ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id); - if (ike_sa == NULL) + if (ike_sa) { - return DESTROY_ME; + ike_sa->send_keepalive(ike_sa); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } - ike_sa->send_keepalive(ike_sa); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return DESTROY_ME; -} - -/** - * Implements job_t.destroy. - */ -static void destroy(private_send_keepalive_job_t *this) -{ - this->ike_sa_id->destroy(this->ike_sa_id); - free(this); + destroy(this); } /* @@ -89,15 +80,12 @@ send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id) private_send_keepalive_job_t *this = malloc_thing(private_send_keepalive_job_t); /* interface functions */ - this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; this->public.job_interface.destroy = (void (*) (job_t *)) destroy; - this->public.job_interface.execute = (status_t (*) (job_t *)) execute; - - /* public functions */ - this->public.destroy = (void (*)(send_keepalive_job_t *)) destroy; + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; /* private variables */ this->ike_sa_id = ike_sa_id->clone(ike_sa_id); - return &(this->public); + return &this->public; } diff --git a/src/charon/processing/jobs/send_keepalive_job.h b/src/charon/processing/jobs/send_keepalive_job.h index f7b38337e..e8d214aed 100644 --- a/src/charon/processing/jobs/send_keepalive_job.h +++ b/src/charon/processing/jobs/send_keepalive_job.h @@ -44,13 +44,6 @@ struct send_keepalive_job_t { * implements job_t interface */ job_t job_interface; - - /** - * @brief Destroys an send_keepalive_job_t object. - * - * @param this send_keepalive_job_t object to destroy - */ - void (*destroy) (send_keepalive_job_t *this); }; /** diff --git a/src/charon/processing/processor.c b/src/charon/processing/processor.c new file mode 100644 index 000000000..b3815eeb1 --- /dev/null +++ b/src/charon/processing/processor.c @@ -0,0 +1,233 @@ +/** + * @file processor.c + * + * @brief Implementation of processor_t. + * + */ + +/* + * Copyright (C) 2005-2007 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 <stdlib.h> +#include <pthread.h> +#include <string.h> +#include <errno.h> + +#include "processor.h" + +#include <daemon.h> +#include <utils/linked_list.h> + + +typedef struct private_processor_t private_processor_t; + +/** + * @brief Private data of processor_t class. + */ +struct private_processor_t { + /** + * Public processor_t interface. + */ + processor_t public; + + /** + * Number of running threads + */ + u_int total_threads; + + /** + * Desired number of threads + */ + u_int desired_threads; + + /** + * Number of threads waiting for work + */ + u_int idle_threads; + + /** + * The jobs are stored in a linked list + */ + linked_list_t *list; + + /** + * access to linked_list is locked through this mutex + */ + pthread_mutex_t mutex; + + /** + * Condvar to wait for new jobs + */ + pthread_cond_t condvar; +}; + +static void process_jobs(private_processor_t *this); + +/** + * restart a terminated thread + */ +static void restart(private_processor_t *this) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, (void*)process_jobs, this) != 0) + { + this->total_threads--; + } +} + +/** + * Process queued jobs, called by the worker threads + */ +static void process_jobs(private_processor_t *this) +{ + int oldstate; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + + DBG2(DBG_JOB, "started worker thread, thread_ID: %06u", (int)pthread_self()); + + pthread_mutex_lock(&this->mutex); + while (this->desired_threads >= this->total_threads) + { + job_t *job; + + if (this->list->get_count(this->list) == 0) + { + this->idle_threads++; + pthread_cond_wait(&this->condvar, &this->mutex); + this->idle_threads--; + continue; + } + this->list->remove_first(this->list, (void**)&job); + pthread_mutex_unlock(&this->mutex); + /* terminated threads are restarted, so we have a constant pool */ + pthread_cleanup_push((void*)restart, this); + job->execute(job); + pthread_cleanup_pop(0); + pthread_mutex_lock(&this->mutex); + } + this->total_threads--; + pthread_cond_broadcast(&this->condvar); + pthread_mutex_unlock(&this->mutex); +} + +/** + * Implementation of processor_t.get_total_threads. + */ +static u_int get_total_threads(private_processor_t *this) +{ + return this->total_threads; +} + +/** + * Implementation of processor_t.get_idle_threads. + */ +static u_int get_idle_threads(private_processor_t *this) +{ + return this->idle_threads; +} + +/** + * implements processor_t.get_job_load + */ +static u_int get_job_load(private_processor_t *this) +{ + u_int load; + pthread_mutex_lock(&this->mutex); + load = this->list->get_count(this->list); + pthread_mutex_unlock(&this->mutex); + return load; +} + +/** + * implements function processor_t.queue_job + */ +static void queue_job(private_processor_t *this, job_t *job) +{ + pthread_mutex_lock(&this->mutex); + this->list->insert_last(this->list, job); + pthread_mutex_unlock(&this->mutex); + pthread_cond_signal(&this->condvar); +} + +/** + * Implementation of processor_t.set_threads. + */ +static void set_threads(private_processor_t *this, u_int count) +{ + pthread_mutex_lock(&this->mutex); + if (count > this->total_threads) + { /* increase thread count */ + int i; + pthread_t current; + + this->desired_threads = count; + DBG1(DBG_JOB, "spawning %d worker threads", count - this->total_threads); + for (i = this->total_threads; i < count; i++) + { + if (pthread_create(¤t, NULL, (void*)process_jobs, this) == 0) + { + this->total_threads++; + } + } + } + else if (count < this->total_threads) + { /* decrease thread count */ + this->desired_threads = count; + } + pthread_mutex_unlock(&this->mutex); +} + +/** + * Implementation of processor_t.destroy. + */ +static void destroy(private_processor_t *this) +{ + set_threads(this, 0); + while (this->total_threads > 0) + { + pthread_cond_broadcast(&this->condvar); + pthread_cond_wait(&this->condvar, &this->mutex); + } + this->list->destroy_offset(this->list, offsetof(job_t, destroy)); + free(this); +} + +/* + * Described in header. + */ +processor_t *processor_create(size_t pool_size) +{ + private_processor_t *this = malloc_thing(private_processor_t); + + this->public.get_total_threads = (u_int(*)(processor_t*))get_total_threads; + this->public.get_idle_threads = (u_int(*)(processor_t*))get_idle_threads; + this->public.get_job_load = (u_int(*)(processor_t*))get_job_load; + this->public.queue_job = (void(*)(processor_t*, job_t*))queue_job; + this->public.set_threads = (void(*)(processor_t*, u_int))set_threads; + this->public.destroy = (void(*)(processor_t*))destroy; + + this->list = linked_list_create(); + pthread_mutex_init(&this->mutex, NULL); + pthread_cond_init(&this->condvar, NULL); + this->total_threads = 0; + this->desired_threads = 0; + this->idle_threads = 0; + + return &this->public; +} + diff --git a/src/charon/processing/processor.h b/src/charon/processing/processor.h new file mode 100644 index 000000000..f12c7f10e --- /dev/null +++ b/src/charon/processing/processor.h @@ -0,0 +1,111 @@ +/** + * @file processor.h + * + * @brief Interface of processor_t. + * + */ + +/* + * Copyright (C) 2005-2007 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. + */ + +#ifndef PROCESSOR_H_ +#define PROCESSOR_H_ + +typedef struct processor_t processor_t; + +#include <stdlib.h> + +#include <library.h> +#include <processing/jobs/job.h> + +/** + * @brief The processor uses threads to process queued jobs. + * + * @b Constructors: + * - processor_create() + * + * @ingroup processing + */ +struct processor_t { + + /** + * @brief Get the total number of threads used by the processor. + * + * @param this calling object + * @return size of thread pool + */ + u_int (*get_total_threads) (processor_t *this); + + /** + * @brief Get the number of threads currently waiting. + * + * @param this calling object + * @return number of idle threads + */ + u_int (*get_idle_threads) (processor_t *this); + + /** + * @brief Get the number of queued jobs. + * + * @param this calling object + * @returns number of items in queue + */ + u_int (*get_job_load) (processor_t *this); + + /** + * @brief Adds a job to the queue. + * + * This function is non blocking and adds a job_t to the queue. + * + * @param this calling object + * @param job job to add to the queue + */ + void (*queue_job) (processor_t *this, job_t *job); + + /** + * @brief Set the number of threads to use in the processor. + * + * If the number of threads is smaller than number of currently running + * threads, thread count is decreased. Use 0 to disable the processor. + * This call blocks if it decreases thread count until threads have + * terminated, so make sure there are not too many blocking jobs. + * + * @param this calling object + * @param count number of threads to allocate + */ + void (*set_threads)(processor_t *this, u_int count); + + /** + * @brief Destroy a processor object. + * + * @param processor calling object + */ + void (*destroy) (processor_t *processor); +}; + +/** + * @brief Create the thread pool without any threads. + * + * Use the set_threads method to start processing jobs. + * + * @return processor_t object + * + * @ingroup processing + */ +processor_t *processor_create(); + +#endif /*PROCESSOR_H_*/ + diff --git a/src/charon/processing/scheduler.c b/src/charon/processing/scheduler.c index 7249e43e6..2706585b0 100644 --- a/src/charon/processing/scheduler.c +++ b/src/charon/processing/scheduler.c @@ -23,12 +23,39 @@ #include <stdlib.h> #include <pthread.h> +#include <sys/time.h> #include "scheduler.h" #include <daemon.h> -#include <processing/job_queue.h> +#include <processing/processor.h> +#include <processing/jobs/callback_job.h> +typedef struct event_t event_t; + +/** + * Event containing a job and a schedule time + */ +struct event_t { + /** + * Time to fire the event. + */ + timeval_t time; + + /** + * Every event has its assigned job. + */ + job_t *job; +}; + +/** + * destroy an event and its job + */ +static void event_destroy(event_t *event) +{ + event->job->destroy(event->job); + free(event); +} typedef struct private_scheduler_t private_scheduler_t; @@ -42,36 +69,164 @@ struct private_scheduler_t { scheduler_t public; /** - * Assigned thread. + * Job wich schedules */ - pthread_t assigned_thread; + callback_job_t *job; + + /** + * The jobs are scheduled in a list. + */ + linked_list_t *list; + + /** + * Exclusive access to list + */ + pthread_mutex_t mutex; + + /** + * Condvar to wait for next job. + */ + pthread_cond_t condvar; }; /** - * Implementation of private_scheduler_t.get_events. + * Returns the difference of two timeval structs in milliseconds + */ +static long time_difference(timeval_t *end, timeval_t *start) +{ + time_t s; + suseconds_t us; + + s = end->tv_sec - start->tv_sec; + us = end->tv_usec - start->tv_usec; + return (s * 1000 + us/1000); +} + +/** + * Get events from the queue and pass it to the processor */ -static void get_events(private_scheduler_t * this) +static job_requeue_t schedule(private_scheduler_t * this) { - job_t *current_job; + timespec_t timeout; + timeval_t now; + event_t *event; + long difference; + int oldstate; + bool timed = FALSE; - /* cancellation disabled by default */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + DBG2(DBG_JOB, "waiting for next event..."); + pthread_mutex_lock(&this->mutex); - DBG1(DBG_JOB, "scheduler thread running, thread_ID: %06u", - (int)pthread_self()); + gettimeofday(&now, NULL); + + if (this->list->get_count(this->list) > 0) + { + this->list->get_first(this->list, (void **)&event); + difference = time_difference(&now, &event->time); + if (difference > 0) + { + DBG2(DBG_JOB, "got event, queueing job for execution"); + this->list->remove_first(this->list, (void **)&event); + pthread_mutex_unlock(&this->mutex); + charon->processor->queue_job(charon->processor, event->job); + free(event); + return JOB_REQUEUE_DIRECT; + } + timeout.tv_sec = event->time.tv_sec; + timeout.tv_nsec = event->time.tv_usec * 1000; + timed = TRUE; + } + pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + + if (timed) + { + pthread_cond_timedwait(&this->condvar, &this->mutex, &timeout); + } + else + { + pthread_cond_wait(&this->condvar, &this->mutex); + } + pthread_setcancelstate(oldstate, NULL); + pthread_cleanup_pop(0); + + pthread_mutex_unlock(&this->mutex); + return JOB_REQUEUE_DIRECT; +} - charon->drop_capabilities(charon, TRUE); +/** + * Implements scheduler_t.get_job_load + */ +static u_int get_job_load(private_scheduler_t *this) +{ + int count; + pthread_mutex_lock(&this->mutex); + count = this->list->get_count(this->list); + pthread_mutex_unlock(&this->mutex); + return count; +} - while (TRUE) +/** + * Implements scheduler_t.schedule_job. + */ +static void schedule_job(private_scheduler_t *this, job_t *job, u_int32_t time) +{ + timeval_t now; + event_t *event, *current; + iterator_t *iterator; + time_t s; + suseconds_t us; + + event = malloc_thing(event_t); + event->job = job; + + /* calculate absolute time */ + s = time / 1000; + us = (time - s * 1000) * 1000; + gettimeofday(&now, NULL); + event->time.tv_usec = (now.tv_usec + us) % 1000000; + event->time.tv_sec = now.tv_sec + (now.tv_usec + us)/1000000 + s; + + pthread_mutex_lock(&this->mutex); + while(TRUE) { - DBG2(DBG_JOB, "waiting for next event..."); - /* get a job, this block until one is available */ - current_job = charon->event_queue->get(charon->event_queue); - /* queue the job in the job queue, workers will eat them */ - DBG2(DBG_JOB, "got event, adding job %N to job-queue", - job_type_names, current_job->get_type(current_job)); - charon->job_queue->add(charon->job_queue, current_job); + if (this->list->get_count(this->list) == 0) + { + this->list->insert_first(this->list,event); + break; + } + + this->list->get_last(this->list, (void**)¤t); + if (time_difference(&event->time, ¤t->time) >= 0) + { /* new event has to be fired after the last event in list */ + this->list->insert_last(this->list, event); + break; + } + + this->list->get_first(this->list, (void**)¤t); + if (time_difference(&event->time, ¤t->time) < 0) + { /* new event has to be fired before the first event in list */ + this->list->insert_first(this->list, event); + break; + } + + iterator = this->list->create_iterator(this->list, TRUE); + /* first element has not to be checked (already done) */ + iterator->iterate(iterator, (void**)¤t); + while(iterator->iterate(iterator, (void**)¤t)) + { + if (time_difference(&event->time, ¤t->time) <= 0) + { + /* new event has to be fired before the current event in list */ + iterator->insert_before(iterator, event); + break; + } + } + iterator->destroy(iterator); + break; } + pthread_cond_signal(&this->condvar); + pthread_mutex_unlock(&this->mutex); } /** @@ -79,8 +234,8 @@ static void get_events(private_scheduler_t * this) */ static void destroy(private_scheduler_t *this) { - pthread_cancel(this->assigned_thread); - pthread_join(this->assigned_thread, NULL); + this->job->cancel(this->job); + this->list->destroy_function(this->list, (void*)event_destroy); free(this); } @@ -91,14 +246,17 @@ scheduler_t * scheduler_create() { private_scheduler_t *this = malloc_thing(private_scheduler_t); + this->public.get_job_load = (u_int (*) (scheduler_t *this)) get_job_load; + this->public.schedule_job = (void (*) (scheduler_t *this, job_t *job, u_int32_t ms)) schedule_job; this->public.destroy = (void(*)(scheduler_t*)) destroy; - if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))get_events, this) != 0) - { - /* thread could not be created */ - free(this); - charon->kill(charon, "unable to create scheduler thread"); - } + this->list = linked_list_create(); + pthread_mutex_init(&this->mutex, NULL); + pthread_cond_init(&this->condvar, NULL); + + this->job = callback_job_create((callback_job_cb_t)schedule, this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); - return &(this->public); + return &this->public; } + diff --git a/src/charon/processing/scheduler.h b/src/charon/processing/scheduler.h index bea93e7c9..7bde6e638 100644 --- a/src/charon/processing/scheduler.h +++ b/src/charon/processing/scheduler.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -27,14 +27,12 @@ typedef struct scheduler_t scheduler_t; #include <library.h> +#include <processing/jobs/job.h> /** - * @brief The scheduler thread is responsible for timed events. + * @brief The scheduler queues and executes timed events. * - * The scheduler thread takes out jobs from the event-queue and adds them - * to the job-queue. - * - * Starts a thread which does the work, since event-queue is blocking. + * The scheduler stores timed events and passes them to the processor. * * @b Constructors: * - scheduler_create() @@ -44,25 +42,40 @@ typedef struct scheduler_t scheduler_t; struct scheduler_t { /** + * @brief Adds a event to the queue, using a relative time offset. + * + * Schedules a job for execution using a relative time offset. + * + * @param this calling object + * @param job job to schedule + * @param time relative to to schedule job (in ms) + */ + void (*schedule_job) (scheduler_t *this, job_t *job, u_int32_t time); + + /** + * @brief Returns number of jobs scheduled. + * + * @param this calling object + * @return number of scheduled jobs + */ + u_int (*get_job_load) (scheduler_t *this); + + /** * @brief Destroys a scheduler object. * - * @param scheduler calling object + * @param this calling object */ - void (*destroy) (scheduler_t *scheduler); + void (*destroy) (scheduler_t *this); }; /** - * @brief Create a scheduler with its associated thread. - * - * The thread will start to get jobs form the event queue - * and adds them to the job queue. + * @brief Create a scheduler. * - * @return - * - scheduler_t object - * - NULL if thread could not be started + * @return scheduler_t object * * @ingroup processing */ -scheduler_t * scheduler_create(void); +scheduler_t *scheduler_create(void); #endif /*SCHEDULER_H_*/ + diff --git a/src/charon/processing/thread_pool.c b/src/charon/processing/thread_pool.c deleted file mode 100644 index a9891da15..000000000 --- a/src/charon/processing/thread_pool.c +++ /dev/null @@ -1,183 +0,0 @@ -/** - * @file thread_pool.c - * - * @brief Implementation of thread_pool_t. - * - */ - -/* - * 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 <stdlib.h> -#include <pthread.h> -#include <string.h> -#include <errno.h> - -#include "thread_pool.h" - -#include <daemon.h> -#include <processing/job_queue.h> - - -typedef struct private_thread_pool_t private_thread_pool_t; - -/** - * @brief Private data of thread_pool_t class. - */ -struct private_thread_pool_t { - /** - * Public thread_pool_t interface. - */ - thread_pool_t public; - - /** - * Number of running threads. - */ - u_int pool_size; - - /** - * Number of threads waiting for work - */ - u_int idle_threads; - - /** - * Array of thread ids. - */ - pthread_t *threads; -}; - -/** - * Implementation of private_thread_pool_t.process_jobs. - */ -static void process_jobs(private_thread_pool_t *this) -{ - job_t *job; - status_t status; - - /* cancellation disabled by default */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - - DBG1(DBG_JOB, "worker thread running, thread_ID: %06u", - (int)pthread_self()); - - charon->drop_capabilities(charon, TRUE); - - while (TRUE) - { - /* TODO: should be atomic, but is not mission critical */ - this->idle_threads++; - job = charon->job_queue->get(charon->job_queue); - this->idle_threads--; - - status = job->execute(job); - - if (status == DESTROY_ME) - { - job->destroy(job); - } - } -} - -/** - * Implementation of thread_pool_t.get_pool_size. - */ -static u_int get_pool_size(private_thread_pool_t *this) -{ - return this->pool_size; -} - -/** - * Implementation of thread_pool_t.get_idle_threads. - */ -static u_int get_idle_threads(private_thread_pool_t *this) -{ - return this->idle_threads; -} - -/** - * Implementation of thread_pool_t.destroy. - */ -static void destroy(private_thread_pool_t *this) -{ - int current; - /* flag thread for termination */ - for (current = 0; current < this->pool_size; current++) - { - DBG1(DBG_JOB, "cancelling worker thread #%d", current+1); - pthread_cancel(this->threads[current]); - } - - /* wait for all threads */ - for (current = 0; current < this->pool_size; current++) { - if (pthread_join(this->threads[current], NULL) == 0) - { - DBG1(DBG_JOB, "worker thread #%d terminated", current+1); - } - else - { - DBG1(DBG_JOB, "could not terminate worker thread #%d", current+1); - } - } - - /* free mem */ - free(this->threads); - free(this); -} - -/* - * Described in header. - */ -thread_pool_t *thread_pool_create(size_t pool_size) -{ - int current; - private_thread_pool_t *this = malloc_thing(private_thread_pool_t); - - /* fill in public fields */ - this->public.destroy = (void(*)(thread_pool_t*))destroy; - this->public.get_pool_size = (u_int(*)(thread_pool_t*))get_pool_size; - this->public.get_idle_threads = (u_int(*)(thread_pool_t*))get_idle_threads; - - /* initialize member */ - this->pool_size = pool_size; - this->idle_threads = 0; - this->threads = malloc(sizeof(pthread_t) * pool_size); - - /* try to create as many threads as possible, up to pool_size */ - for (current = 0; current < pool_size; current++) - { - if (pthread_create(&(this->threads[current]), NULL, - (void*(*)(void*))process_jobs, this) == 0) - { - DBG1(DBG_JOB, "created worker thread #%d", current+1); - } - else - { - /* creation failed, is it the first one? */ - if (current == 0) - { - free(this->threads); - free(this); - charon->kill(charon, "could not create any worker threads"); - } - /* not all threads could be created, but at least one :-/ */ - DBG1(DBG_JOB, "could only create %d from requested %d threads!", - current, pool_size); - this->pool_size = current; - break; - } - } - return (thread_pool_t*)this; -} diff --git a/src/charon/processing/thread_pool.h b/src/charon/processing/thread_pool.h deleted file mode 100644 index 09a6312a8..000000000 --- a/src/charon/processing/thread_pool.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file thread_pool.h - * - * @brief Interface of thread_pool_t. - * - */ - -/* - * 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. - */ - -#ifndef THREAD_POOL_H_ -#define THREAD_POOL_H_ - -typedef struct thread_pool_t thread_pool_t; - -#include <stdlib.h> - -#include <library.h> - -/** - * @brief A thread_pool consists of a pool of threads processing jobs from the job queue. - * - * Current implementation uses as many threads as specified in constructor. - * A more improved version would dynamically increase thread count if necessary. - * - * @b Constructors: - * - thread_pool_create() - * - * @todo Add support for dynamic thread handling - * - * @ingroup processing - */ -struct thread_pool_t { - - /** - * @brief Return currently instanciated thread count. - * - * @param thread_pool calling object - * @return size of thread pool - */ - u_int (*get_pool_size) (thread_pool_t *thread_pool); - - /** - * @brief Get the number of threads currently waiting for work. - * - * @param thread_pool calling object - * @return number of idle threads - */ - u_int (*get_idle_threads) (thread_pool_t *thread_pool); - - /** - * @brief Destroy a thread_pool_t object. - * - * Sends cancellation request to all threads and AWAITS their termination. - * - * @param thread_pool calling object - */ - void (*destroy) (thread_pool_t *thread_pool); -}; - -/** - * @brief Create the thread pool using using pool_size of threads. - * - * @param pool_size desired pool size - * @return - * - thread_pool_t object if one ore more threads could be started, or - * - NULL if no threads could be created - * - * @ingroup processing - */ -thread_pool_t *thread_pool_create(size_t pool_size); - - -#endif /*THREAD_POOL_H_*/ diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 1e7b6cb2c..118af3b30 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -60,7 +60,7 @@ struct sa_policy_t { typedef struct private_child_sa_t private_child_sa_t; /** - * Private data of a child_sa_t bject. + * Private data of a child_sa_t object. */ struct private_child_sa_t { /** @@ -138,9 +138,9 @@ struct private_child_sa_t { child_sa_state_t state; /** - * Specifies if NAT traversal is used + * Specifies if UDP encapsulation is enabled (NAT traversal) */ - bool use_natt; + bool encap; /** * mode this SA uses, tunnel/transport @@ -156,6 +156,11 @@ struct private_child_sa_t { * config used to create this child */ child_cfg_t *config; + + /** + * cached interface name for iptables + */ + char *iface; }; /** @@ -276,11 +281,10 @@ static void updown(private_child_sa_t *this, bool up) while (iterator->iterate(iterator, (void**)&policy)) { char command[1024]; - char *ifname = NULL; char *my_client, *other_client, *my_client_mask, *other_client_mask; char *pos, *virtual_ip; FILE *shell; - + /* get subnet/bits from string */ asprintf(&my_client, "%R", policy->my_ts); pos = strchr(my_client, '/'); @@ -301,18 +305,24 @@ static void updown(private_child_sa_t *this, bool up) *pos = '\0'; } - if (this->virtual_ip) - { - asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", - this->virtual_ip); - } - else - { - asprintf(&virtual_ip, ""); - } + if (this->virtual_ip) + { + asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", + this->virtual_ip); + } + else + { + asprintf(&virtual_ip, ""); + } - ifname = charon->kernel_interface->get_interface(charon->kernel_interface, - this->me.addr); + /* we cache the iface name, as it may not be available when + * the SA gets deleted */ + if (up) + { + free(this->iface); + this->iface = charon->kernel_interface->get_interface( + charon->kernel_interface, this->me.addr); + } /* build the command with all env variables. * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing @@ -346,7 +356,7 @@ static void updown(private_child_sa_t *this, bool up) this->me.addr) ? "-host" : "-client", this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6", this->config->get_name(this->config), - ifname ? ifname : "(unknown)", + this->iface ? this->iface : "unknown", this->reqid, this->me.addr, this->me.id, @@ -364,11 +374,11 @@ static void updown(private_child_sa_t *this, bool up) this->config->get_hostaccess(this->config) ? "PLUTO_HOST_ACCESS='1' " : "", script); - free(ifname); free(my_client); free(other_client); free(virtual_ip); + DBG3(DBG_CHD, "running updown script: %s", command); shell = popen(command, "r"); if (shell == NULL) @@ -494,7 +504,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, algorithm_t int_algo_none = {AUTH_UNDEFINED, 0}; host_t *src; host_t *dst; - natt_conf_t *natt; status_t status; this->protocol = proposal->get_protocol(proposal); @@ -561,18 +570,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, int_algo = &int_algo_none; } - /* setup nat-t */ - if (this->use_natt) - { - natt = alloca(sizeof(natt_conf_t)); - natt->sport = src->get_port(src); - natt->dport = dst->get_port(dst); - } - else - { - natt = NULL; - } - soft = this->config->get_lifetime(this->config, TRUE); hard = this->config->get_lifetime(this->config, FALSE); @@ -582,7 +579,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, enc_algo, int_algo, - prf_plus, natt, mode, mine); + prf_plus, mode, this->encap, mine); this->encryption = *enc_algo; this->integrity = *int_algo; @@ -689,15 +686,15 @@ static status_t add_policies(private_child_sa_t *this, /* install 3 policies: out, in and forward */ status = charon->kernel_interface->add_policy(charon->kernel_interface, this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT, - this->protocol, this->reqid, high_prio, mode, FALSE); + this->protocol, this->reqid, high_prio, mode); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN, - this->protocol, this->reqid, high_prio, mode, FALSE); + this->protocol, this->reqid, high_prio, mode); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD, - this->protocol, this->reqid, high_prio, mode, FALSE); + this->protocol, this->reqid, high_prio, mode); if (status != SUCCESS) { @@ -782,139 +779,89 @@ static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use } /** - * Update the host adress/port of a SA - */ -static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, - int my_changes, int other_changes, bool mine) -{ - host_t *src, *dst, *new_src, *new_dst; - int src_changes, dst_changes; - status_t status; - u_int32_t spi; - - if (mine) - { - src = this->other.addr; - dst = this->me.addr; - new_src = new_other; - new_dst = new_me; - src_changes = other_changes; - dst_changes = my_changes; - spi = this->other.spi; - } - else - { - src = this->me.addr; - dst = this->other.addr; - new_src = new_me; - new_dst = new_other; - src_changes = my_changes; - dst_changes = other_changes; - spi = this->me.spi; - } - - DBG2(DBG_CHD, "updating %N SA 0x%x, from %#H..#H to %#H..%#H", - protocol_id_names, this->protocol, ntohl(spi), src, dst, new_src, new_dst); - - status = charon->kernel_interface->update_sa(charon->kernel_interface, - dst, spi, this->protocol, - new_src, new_dst, - src_changes, dst_changes); - - if (status != SUCCESS) - { - return FAILED; - } - return SUCCESS; -} - -/** - * Update the host adress/port of a policy - */ -static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other) -{ - iterator_t *iterator; - sa_policy_t *policy; - status_t status; - /* we always use high priorities, as hosts getting updated are INSTALLED */ - - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) - { - status = charon->kernel_interface->add_policy( - charon->kernel_interface, - new_me, new_other, - policy->my_ts, policy->other_ts, - POLICY_OUT, this->protocol, this->reqid, TRUE, this->mode, TRUE); - - status |= charon->kernel_interface->add_policy( - charon->kernel_interface, - new_other, new_me, - policy->other_ts, policy->my_ts, - POLICY_IN, this->protocol, this->reqid, TRUE, this->mode, TRUE); - - status |= charon->kernel_interface->add_policy( - charon->kernel_interface, - new_other, new_me, - policy->other_ts, policy->my_ts, - POLICY_FWD, this->protocol, this->reqid, TRUE, this->mode, TRUE); - - if (status != SUCCESS) - { - iterator->destroy(iterator); - return FAILED; - } - } - iterator->destroy(iterator); - - return SUCCESS; -} - -/** * Implementation of child_sa_t.update_hosts. */ -static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, - host_diff_t my_changes, host_diff_t other_changes) +static status_t update_hosts(private_child_sa_t *this, + host_t *me, host_t *other, bool encap) { - if (!my_changes && !other_changes) + /* anything changed at all? */ + if (me->equals(me, this->me.addr) && + other->equals(other, this->other.addr) && this->encap == encap) { return SUCCESS; } - + /* run updown script to remove iptables rules */ + updown(this, FALSE); + + this->encap = encap; + /* update our (initator) SAs */ - if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, TRUE) != SUCCESS) - { - return FAILED; - } - + charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi, + this->protocol, this->other.addr, this->me.addr, other, me, encap); /* update his (responder) SAs */ - if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, FALSE) != SUCCESS) - { - return FAILED; - } + charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi, + this->protocol, this->me.addr, this->other.addr, me, other, encap); /* update policies */ - if (my_changes & HOST_DIFF_ADDR || other_changes & HOST_DIFF_ADDR) + if (!me->ip_equals(me, this->me.addr) || + !other->ip_equals(other, this->other.addr)) { - if (update_policy_hosts(this, new_me, new_other) != SUCCESS) + iterator_t *iterator; + sa_policy_t *policy; + + /* always use high priorities, as hosts getting updated are INSTALLED */ + iterator = this->policies->create_iterator(this->policies, TRUE); + while (iterator->iterate(iterator, (void**)&policy)) { - return FAILED; + /* remove old policies first */ + charon->kernel_interface->del_policy(charon->kernel_interface, + policy->my_ts, policy->other_ts, POLICY_OUT); + charon->kernel_interface->del_policy(charon->kernel_interface, + policy->other_ts, policy->my_ts, POLICY_IN); + charon->kernel_interface->del_policy(charon->kernel_interface, + policy->other_ts, policy->my_ts, POLICY_FWD); + + /* check wether we have to update a "dynamic" traffic selector */ + if (!me->ip_equals(me, this->me.addr) && + policy->my_ts->is_host(policy->my_ts, this->me.addr)) + { + policy->my_ts->set_address(policy->my_ts, me); + } + if (!other->ip_equals(other, this->other.addr) && + policy->other_ts->is_host(policy->other_ts, this->other.addr)) + { + policy->other_ts->set_address(policy->other_ts, other); + } + + /* reinstall updated policies */ + charon->kernel_interface->add_policy(charon->kernel_interface, + me, other, policy->my_ts, policy->other_ts, POLICY_OUT, + this->protocol, this->reqid, TRUE, this->mode); + charon->kernel_interface->add_policy(charon->kernel_interface, + other, me, policy->other_ts, policy->my_ts, POLICY_IN, + this->protocol, this->reqid, TRUE, this->mode); + charon->kernel_interface->add_policy(charon->kernel_interface, + other, me, policy->other_ts, policy->my_ts, POLICY_FWD, + this->protocol, this->reqid, TRUE, this->mode); } + iterator->destroy(iterator); } - /* update hosts */ - if (my_changes) + /* apply hosts */ + if (!me->equals(me, this->me.addr)) { this->me.addr->destroy(this->me.addr); - this->me.addr = new_me->clone(new_me); + this->me.addr = me->clone(me); } - - if (other_changes) + if (!other->equals(other, this->other.addr)) { this->other.addr->destroy(this->other.addr); - this->other.addr = new_other->clone(new_other); - } - + this->other.addr = other->clone(other); + } + + /* install new iptables rules */ + updown(this, TRUE); + return SUCCESS; } @@ -988,6 +935,7 @@ static void destroy(private_child_sa_t *this) this->me.id->destroy(this->me.id); this->other.id->destroy(this->other.id); this->config->destroy(this->config); + free(this->iface); DESTROY_IF(this->virtual_ip); free(this); } @@ -997,7 +945,7 @@ static void destroy(private_child_sa_t *this) */ child_sa_t * child_sa_create(host_t *me, host_t* other, identification_t *my_id, identification_t *other_id, - child_cfg_t *config, u_int32_t rekey, bool use_natt) + child_cfg_t *config, u_int32_t rekey, bool encap) { static u_int32_t reqid = 0; private_child_sa_t *this = malloc_thing(private_child_sa_t); @@ -1011,7 +959,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add; this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update; - this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts; + this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,bool))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies; this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; @@ -1030,7 +978,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->other.spi = 0; this->alloc_ah_spi = 0; this->alloc_esp_spi = 0; - this->use_natt = use_natt; + this->encap = encap; this->state = CHILD_CREATED; /* reuse old reqid if we are rekeying an existing CHILD_SA */ this->reqid = rekey ? rekey : ++reqid; @@ -1044,6 +992,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->protocol = PROTO_NONE; this->mode = MODE_TUNNEL; this->virtual_ip = NULL; + this->iface = NULL; this->config = config; config->get_ref(config); diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index cf5f3e7d7..b801dd012 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -35,11 +35,6 @@ typedef struct child_sa_t child_sa_t; #include <config/child_cfg.h> /** - * Where we should start with reqid enumeration - */ -#define REQID_START 2000000000 - -/** * @brief States of a CHILD_SA */ enum child_sa_state_t { @@ -200,19 +195,18 @@ struct child_sa_t { prf_plus_t *prf_plus); /** - * @brief Update the hosts in the kernel SAs and policies + * @brief Update the hosts in the kernel SAs and policies. * - * @warning only call this after update() has been called. + * The CHILD must be INSTALLED to do this update. * - * @param this calling object - * @param new_me the new local host - * @param new_other the new remote host - * @param my_diff differences to apply for me - * @param other_diff differences to apply for other - * @return SUCCESS or FAILED + * @param this calling object + * @param me the new local host + * @param other the new remote host + * @param TRUE to use UDP encapsulation for NAT traversal + * @return SUCCESS or FAILED */ - status_t (*update_hosts)(child_sa_t *this, host_t *new_me, host_t *new_other, - host_diff_t my_diff, host_diff_t other_diff); + status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other, + bool encap); /** * @brief Install the policies using some traffic selectors. @@ -298,13 +292,13 @@ struct child_sa_t { * @param other_id id of remote peer * @param config config to use for this CHILD_SA * @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise - * @param use_natt TRUE if NAT traversal is used + * @param encap TRUE to enable UDP encapsulation (NAT traversal) * @return child_sa_t object * * @ingroup sa */ child_sa_t * child_sa_create(host_t *me, host_t *other, identification_t *my_id, identification_t* other_id, - child_cfg_t *config, u_int32_t reqid, bool use_natt); + child_cfg_t *config, u_int32_t reqid, bool encap); #endif /*CHILD_SA_H_*/ diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 8b4b53e10..0a996329d 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -48,10 +48,12 @@ #include <sa/task_manager.h> #include <sa/tasks/ike_init.h> #include <sa/tasks/ike_natd.h> +#include <sa/tasks/ike_mobike.h> #include <sa/tasks/ike_auth.h> #include <sa/tasks/ike_config.h> #include <sa/tasks/ike_cert.h> #include <sa/tasks/ike_rekey.h> +#include <sa/tasks/ike_reauth.h> #include <sa/tasks/ike_delete.h> #include <sa/tasks/ike_dpd.h> #include <sa/tasks/child_create.h> @@ -142,6 +144,16 @@ struct private_ike_sa_t { * CA that issued the certificate of other */ ca_info_t *other_ca; + + /** + * set of extensions the peer supports + */ + ike_extension_t extensions; + + /** + * set of condition flags currently enabled for this IKE_SA + */ + ike_condition_t conditions; /** * Linked List containing the child sa's of the current IKE_SA. @@ -189,16 +201,6 @@ struct private_ike_sa_t { chunk_t skp_verify; /** - * NAT status of local host. - */ - bool nat_here; - - /** - * NAT status of remote host. - */ - bool nat_there; - - /** * Virtual IP on local host, if any */ host_t *my_virtual_ip; @@ -212,6 +214,16 @@ struct private_ike_sa_t { * List of DNS servers installed by us */ linked_list_t *dns_servers; + + /** + * list of peers additional addresses, transmitted via MOBIKE + */ + linked_list_t *additional_addresses; + + /** + * number pending UPDATE_SA_ADDRESS (MOBIKE) + */ + u_int32_t pending_updates; /** * Timestamps for this IKE_SA @@ -356,33 +368,68 @@ static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg) if (this->my_host->is_anyaddr(this->my_host)) { host_t *me = this->ike_cfg->get_my_host(this->ike_cfg); - set_my_host(this, me->clone(me)); } if (this->other_host->is_anyaddr(this->other_host)) { host_t *other = this->ike_cfg->get_other_host(this->ike_cfg); - set_other_host(this, other->clone(other)); } /* apply IDs if they are not already set */ if (this->my_id->contains_wildcards(this->my_id)) { - identification_t *my_id = this->peer_cfg->get_my_id(this->peer_cfg); - DESTROY_IF(this->my_id); - this->my_id = my_id->clone(my_id); + this->my_id = this->peer_cfg->get_my_id(this->peer_cfg); + this->my_id = this->my_id->clone(this->my_id); } if (this->other_id->contains_wildcards(this->other_id)) { - identification_t *other_id = this->peer_cfg->get_other_id(this->peer_cfg); - DESTROY_IF(this->other_id); - this->other_id = other_id->clone(other_id); + this->other_id = this->peer_cfg->get_other_id(this->peer_cfg); + this->other_id = this->other_id->clone(this->other_id); } } /** + * Implementation of ike_sa_t.send_keepalive + */ +static void send_keepalive(private_ike_sa_t *this) +{ + send_keepalive_job_t *job; + time_t last_out, now, diff; + + if (!(this->conditions & COND_NAT_HERE)) + { /* disable keep alives if we are not NATed anymore */ + return; + } + + last_out = get_use_time(this, FALSE); + now = time(NULL); + + diff = now - last_out; + + if (diff >= KEEPALIVE_INTERVAL) + { + packet_t *packet; + chunk_t data; + + packet = packet_create(); + packet->set_source(packet, this->my_host->clone(this->my_host)); + packet->set_destination(packet, this->other_host->clone(this->other_host)); + data.ptr = malloc(1); + data.ptr[0] = 0xFF; + data.len = 1; + packet->set_data(packet, data); + DBG1(DBG_IKE, "sending keep alive"); + charon->sender->send(charon->sender, packet); + diff = 0; + } + job = send_keepalive_job_create(this->ike_sa_id); + charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, + (KEEPALIVE_INTERVAL - diff) * 1000); +} + +/** * Implementation of ike_sa_t.get_ike_cfg */ static ike_cfg_t *get_ike_cfg(private_ike_sa_t *this) @@ -398,6 +445,80 @@ static void set_ike_cfg(private_ike_sa_t *this, ike_cfg_t *ike_cfg) ike_cfg->get_ref(ike_cfg); this->ike_cfg = ike_cfg; } +/** + * Implementation of ike_sa_t.enable_extension. + */ +static void enable_extension(private_ike_sa_t *this, ike_extension_t extension) +{ + this->extensions |= extension; +} + +/** + * Implementation of ike_sa_t.has_extension. + */ +static bool supports_extension(private_ike_sa_t *this, ike_extension_t extension) +{ + return (this->extensions & extension) != FALSE; +} + +/** + * Implementation of ike_sa_t.has_condition. + */ +static bool has_condition(private_ike_sa_t *this, ike_condition_t condition) +{ + return (this->conditions & condition) != FALSE; +} + +/** + * Implementation of ike_sa_t.enable_condition. + */ +static void set_condition(private_ike_sa_t *this, ike_condition_t condition, + bool enable) +{ + if (has_condition(this, condition) != enable) + { + if (enable) + { + 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; + send_keepalive(this); + break; + case COND_NAT_THERE: + DBG1(DBG_IKE, "remote host is behind NAT"); + this->conditions |= COND_NAT_ANY; + break; + default: + break; + } + } + else + { + 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_THERE: + set_condition(this, COND_NAT_ANY, + has_condition(this, COND_NAT_HERE) || + has_condition(this, COND_NAT_THERE)); + break; + default: + break; + } + } + } +} /** * Implementation of ike_sa_t.send_dpd @@ -442,46 +563,12 @@ static status_t send_dpd(private_ike_sa_t *this) } /* recheck in "interval" seconds */ job = send_dpd_job_create(this->ike_sa_id); - charon->event_queue->add_relative(charon->event_queue, (job_t*)job, - (delay - diff) * 1000); + charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, + (delay - diff) * 1000); return SUCCESS; } /** - * Implementation of ike_sa_t.send_keepalive - */ -static void send_keepalive(private_ike_sa_t *this) -{ - send_keepalive_job_t *job; - time_t last_out, now, diff; - - last_out = get_use_time(this, FALSE); - now = time(NULL); - - diff = now - last_out; - - if (diff >= KEEPALIVE_INTERVAL) - { - packet_t *packet; - chunk_t data; - - packet = packet_create(); - packet->set_source(packet, this->my_host->clone(this->my_host)); - packet->set_destination(packet, this->other_host->clone(this->other_host)); - data.ptr = malloc(1); - data.ptr[0] = 0xFF; - data.len = 1; - packet->set_data(packet, data); - charon->sender->send(charon->sender, packet); - DBG1(DBG_IKE, "sending keep alive"); - diff = 0; - } - job = send_keepalive_job_create(this->ike_sa_id); - charon->event_queue->add_relative(charon->event_queue, (job_t*)job, - (KEEPALIVE_INTERVAL - diff) * 1000); -} - -/** * Implementation of ike_sa_t.get_state. */ static ike_sa_state_t get_state(private_ike_sa_t *this) @@ -524,16 +611,16 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) { this->time.rekey = now + soft; job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth); - charon->event_queue->add_relative(charon->event_queue, job, - soft * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, + soft * 1000); } if (hard) { this->time.delete = now + hard; job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->event_queue->add_relative(charon->event_queue, job, - hard * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, + hard * 1000); } } break; @@ -542,8 +629,8 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) { /* delete may fail if a packet gets lost, so set a timeout */ job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->event_queue->add_relative(charon->event_queue, job, - HALF_OPEN_IKE_SA_TIMEOUT); + charon->scheduler->schedule_job(charon->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); break; } default: @@ -570,67 +657,151 @@ static void reset(private_ike_sa_t *this) } /** + * Implementation of ike_sa_t.set_virtual_ip + */ +static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip) +{ + if (local) + { + DBG1(DBG_IKE, "installing new virtual IP %H", ip); + 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); + } + if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, + this->my_host) == SUCCESS) + { + this->my_virtual_ip = ip->clone(ip); + } + else + { + DBG1(DBG_IKE, "installing virtual IP %H failed", ip); + this->my_virtual_ip = NULL; + } + } + else + { + DESTROY_IF(this->other_virtual_ip); + this->other_virtual_ip = ip->clone(ip); + } +} + +/** + * Implementation of ike_sa_t.get_virtual_ip + */ +static host_t* get_virtual_ip(private_ike_sa_t *this, bool local) +{ + if (local) + { + return this->my_virtual_ip; + } + else + { + return this->other_virtual_ip; + } +} + +/** + * Implementation of ike_sa_t.add_additional_address. + */ +static void add_additional_address(private_ike_sa_t *this, host_t *host) +{ + this->additional_addresses->insert_last(this->additional_addresses, host); +} + +/** + * Implementation of ike_sa_t.create_additional_address_iterator. + */ +static iterator_t* create_additional_address_iterator(private_ike_sa_t *this) +{ + return this->additional_addresses->create_iterator( + this->additional_addresses, TRUE); +} + +/** + * Implementation of ike_sa_t.set_pending_updates. + */ +static void set_pending_updates(private_ike_sa_t *this, u_int32_t updates) +{ + this->pending_updates = updates; +} + +/** + * Implementation of ike_sa_t.get_pending_updates. + */ +static u_int32_t get_pending_updates(private_ike_sa_t *this) +{ + return this->pending_updates; +} + +/** * Update hosts, as addresses may change (NAT) */ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) { - iterator_t *iterator = NULL; - child_sa_t *child_sa = NULL; - host_diff_t my_diff, other_diff; + bool update = FALSE; - if (this->my_host->is_anyaddr(this->my_host) || - this->other_host->is_anyaddr(this->other_host)) - { - /* on first received message */ - this->my_host->destroy(this->my_host); - this->my_host = me->clone(me); - this->other_host->destroy(this->other_host); - this->other_host = other->clone(other); + if (supports_extension(this, EXT_MOBIKE)) + { /* if peer speaks mobike, address updates are explicit only */ return; } - my_diff = me->get_differences(me, this->my_host); - other_diff = other->get_differences(other, this->other_host); - - if (!my_diff && !other_diff) + if (me == NULL) { - return; + me = this->my_host; } - - if (my_diff) + if (other == NULL) { - this->my_host->destroy(this->my_host); - this->my_host = me->clone(me); + other = this->other_host; } - if (!this->nat_here) + /* apply hosts on first received message */ + if (this->my_host->is_anyaddr(this->my_host) || + this->other_host->is_anyaddr(this->other_host)) { - /* update without restrictions if we are not NATted */ - if (other_diff) - { - this->other_host->destroy(this->other_host); - this->other_host = other->clone(other); - } + set_my_host(this, me->clone(me)); + set_other_host(this, other->clone(other)); + update = TRUE; } else { - /* if we are natted, only port may change */ - if (other_diff & HOST_DIFF_ADDR) + /* update our address in any case */ + if (!me->equals(me, this->my_host)) { - return; + set_my_host(this, me->clone(me)); + update = TRUE; } - else if (other_diff & HOST_DIFF_PORT) + + if (!other->equals(other, this->other_host)) { - this->other_host->set_port(this->other_host, other->get_port(other)); + /* update others adress if we are NOT NATed, + * and allow port changes if we are NATed */ + if (!has_condition(this, COND_NAT_HERE) || + other->ip_equals(other, this->other_host)) + { + set_other_host(this, other->clone(other)); + update = TRUE; + } } } - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) + + /* update all associated CHILD_SAs, if required */ + if (update) { - child_sa->update_hosts(child_sa, this->my_host, this->other_host, - my_diff, other_diff); + iterator_t *iterator; + child_sa_t *child_sa; + + iterator = this->child_sas->create_iterator(this->child_sas, TRUE); + while (iterator->iterate(iterator, (void**)&child_sa)) + { + child_sa->update_hosts(child_sa, this->my_host, this->other_host, + has_condition(this, COND_NAT_ANY)); + } + iterator->destroy(iterator); } - iterator->destroy(iterator); } /** @@ -761,12 +932,12 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) } /* add a timeout if peer does not establish it completely */ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); - charon->event_queue->add_relative(charon->event_queue, job, - HALF_OPEN_IKE_SA_TIMEOUT); + charon->scheduler->schedule_job(charon->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); } /* check if message is trustworthy, and update host information */ - if (this->state == IKE_CREATED || + if (this->state == IKE_CREATED || this->state == IKE_CONNECTING || message->get_exchange_type(message) != IKE_SA_INIT) { update_hosts(this, me, other); @@ -788,6 +959,7 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) if (this->other_host->is_anyaddr(this->other_host)) { + child_cfg->destroy(child_cfg); SIG(IKE_UP_START, "initiating IKE_SA"); SIG(IKE_UP_FAILED, "unable to initiate to %%any"); return DESTROY_ME; @@ -803,6 +975,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_mobike_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); } task = (task_t*)child_create_create(&this->public, child_cfg); @@ -863,6 +1037,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_mobike_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); } child_cfg = child_sa->get_config(child_sa); @@ -881,6 +1057,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) child_sa_t *child_sa; iterator_t *iterator; linked_list_t *my_ts, *other_ts; + host_t *me, *other; status_t status; SIG(CHILD_ROUTE_START, "routing CHILD_SA"); @@ -916,11 +1093,19 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) /* install kernel policies */ child_sa = child_sa_create(this->my_host, this->other_host, this->my_id, this->other_id, child_cfg, FALSE, 0); + me = this->my_host; + if (this->my_virtual_ip) + { + me = this->my_virtual_ip; + } + other = this->other_host; + if (this->other_virtual_ip) + { + other = this->other_virtual_ip; + } - my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, - this->my_host); - other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, - this->other_host); + my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, me); + other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, other); status = child_sa->add_policies(child_sa, my_ts, other_ts, child_cfg->get_mode(child_cfg)); my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); @@ -1063,6 +1248,16 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) /* use actual used host, not the wildcarded one in config */ new->other_host->destroy(new->other_host); new->other_host = this->other_host->clone(this->other_host); + /* reset port to 500, but only if peer is not NATed */ + if (!has_condition(this, COND_NAT_THERE)) + { + new->other_host->set_port(new->other_host, IKEV2_UDP_PORT); + } + /* take over virtual ip, as we need it for a proper route */ + if (this->my_virtual_ip) + { + set_virtual_ip(new, TRUE, this->my_virtual_ip); + } /* install routes */ while (to_route->remove_last(to_route, (void**)&child_cfg) == SUCCESS) @@ -1089,6 +1284,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_mobike_create(&new->public, TRUE); + new->task_manager->queue_task(new->task_manager, task); new->task_manager->initiate(new->task_manager); } charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public); @@ -1191,55 +1388,6 @@ static void set_other_ca(private_ike_sa_t *this, ca_info_t *other_ca) } /** - * Implementation of ike_sa_t.set_virtual_ip - */ -static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip) -{ - if (local) - { - DBG1(DBG_IKE, "installing new virtual IP %H", ip); - 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_host); - this->my_virtual_ip->destroy(this->my_virtual_ip); - } - if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, - this->my_host) == SUCCESS) - { - this->my_virtual_ip = ip->clone(ip); - } - else - { - DBG1(DBG_IKE, "installing virtual IP %H failed", ip); - this->my_virtual_ip = NULL; - } - } - else - { - DESTROY_IF(this->other_virtual_ip); - this->other_virtual_ip = ip->clone(ip); - } -} - -/** - * Implementation of ike_sa_t.get_virtual_ip - */ -static host_t* get_virtual_ip(private_ike_sa_t *this, bool local) -{ - if (local) - { - return this->my_virtual_ip; - } - else - { - return this->other_virtual_ip; - } -} - -/** * Implementation of ike_sa_t.derive_keys. */ static status_t derive_keys(private_ike_sa_t *this, @@ -1560,72 +1708,78 @@ static status_t rekey(private_ike_sa_t *this) /** * Implementation of ike_sa_t.reestablish */ -static void reestablish(private_ike_sa_t *this) +static status_t reestablish(private_ike_sa_t *this) { - private_ike_sa_t *other; - iterator_t *iterator; - child_sa_t *child_sa; - child_cfg_t *child_cfg; task_t *task; - job_t *job; - - other = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new( - charon->ike_sa_manager, TRUE); - set_peer_cfg(other, this->peer_cfg); - other->other_host->destroy(other->other_host); - other->other_host = this->other_host->clone(this->other_host); - if (this->my_virtual_ip) - { - /* if we already have a virtual IP, we reuse it */ - set_virtual_ip(other, TRUE, this->my_virtual_ip); - } - - if (this->state == IKE_ESTABLISHED) - { - task = (task_t*)ike_init_create(&other->public, TRUE, NULL); - other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_natd_create(&other->public, TRUE); - other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_cert_create(&other->public, TRUE); - other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_config_create(&other->public, TRUE); - other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_auth_create(&other->public, TRUE); - other->task_manager->queue_task(other->task_manager, task); - } + task = (task_t*)ike_reauth_create(&this->public); + this->task_manager->queue_task(this->task_manager, task); - other->task_manager->adopt_tasks(other->task_manager, this->task_manager); + return this->task_manager->initiate(this->task_manager); +} + +/** + * Implementation of ike_sa_t.roam. + */ +static status_t roam(private_ike_sa_t *this, bool address) +{ + host_t *me, *other; + ike_mobike_t *mobike; - /* Create task for established children, adopt routed children directly */ - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while(iterator->iterate(iterator, (void**)&child_sa)) + /* responder just updates the peer about changed address config */ + if (!this->ike_sa_id->is_initiator(this->ike_sa_id)) { - switch (child_sa->get_state(child_sa)) + if (supports_extension(this, EXT_MOBIKE) && address) { - case CHILD_ROUTED: - { - iterator->remove(iterator); - other->child_sas->insert_first(other->child_sas, child_sa); - break; - } - default: - { - child_cfg = child_sa->get_config(child_sa); - task = (task_t*)child_create_create(&other->public, child_cfg); - other->task_manager->queue_task(other->task_manager, task); - break; - } + DBG1(DBG_IKE, "sending address list update using MOBIKE"); + mobike = ike_mobike_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, (task_t*)mobike); + return this->task_manager->initiate(this->task_manager); } + return SUCCESS; } - iterator->destroy(iterator); - other->task_manager->initiate(other->task_manager); + /* get best address pair to use */ + other = this->other_host; + me = charon->kernel_interface->get_source_addr(charon->kernel_interface, + other); + + /* TODO: find a better path using additional addresses of peer */ - charon->ike_sa_manager->checkin(charon->ike_sa_manager, &other->public); + if (!me) + { + /* no route found to host, set to stale, wait for a new route */ + set_condition(this, COND_STALE, TRUE); + return FAILED; + } + + set_condition(this, COND_STALE, FALSE); + if (me->ip_equals(me, this->my_host) && + other->ip_equals(other, this->other_host)) + { + DBG2(DBG_IKE, "%H still reached through %H, no update needed", + this->other_host, me); + me->destroy(me); + return SUCCESS; + } + me->set_port(me, this->my_host->get_port(this->my_host)); + other = other->clone(other); + other->set_port(other, this->other_host->get_port(this->other_host)); + set_my_host(this, me); + set_other_host(this, other); - job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->job_queue->add(charon->job_queue, job); + /* update addresses with mobike, if supported ... */ + if (supports_extension(this, EXT_MOBIKE)) + { + DBG1(DBG_IKE, "requesting address change using MOBIKE"); + mobike = ike_mobike_create(&this->public, TRUE); + mobike->roam(mobike, address); + this->task_manager->queue_task(this->task_manager, (task_t*)mobike); + return this->task_manager->initiate(this->task_manager); + } + DBG1(DBG_IKE, "reestablishing IKE_SA due address change"); + /* ... reestablish if not */ + return reestablish(this); } /** @@ -1680,32 +1834,6 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) } /** - * Implementation of ike_sa_t.is_natt_enabled. - */ -static bool is_natt_enabled(private_ike_sa_t *this) -{ - return this->nat_here || this->nat_there; -} - -/** - * Implementation of ike_sa_t.enable_natt. - */ -static void enable_natt(private_ike_sa_t *this, bool local) -{ - if (local) - { - DBG1(DBG_IKE, "local host is behind NAT, scheduling keep alives"); - this->nat_here = TRUE; - send_keepalive(this); - } - else - { - DBG1(DBG_IKE, "remote host is behind NAT"); - this->nat_there = TRUE; - } -} - -/** * Implementation of ike_sa_t.remove_dns_server */ static void remove_dns_servers(private_ike_sa_t *this) @@ -1857,13 +1985,16 @@ static void destroy(private_ike_sa_t *this) if (this->my_virtual_ip) { charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip, this->my_host); + this->my_virtual_ip); this->my_virtual_ip->destroy(this->my_virtual_ip); } DESTROY_IF(this->other_virtual_ip); remove_dns_servers(this); - this->dns_servers->destroy_offset(this->dns_servers, offsetof(host_t, destroy)); + this->dns_servers->destroy_offset(this->dns_servers, + offsetof(host_t, destroy)); + this->additional_addresses->destroy_offset(this->additional_addresses, + offsetof(host_t, destroy)); DESTROY_IF(this->my_host); DESTROY_IF(this->other_host); @@ -1905,12 +2036,21 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.set_my_host = (void (*)(ike_sa_t*,host_t*)) set_my_host; this->public.get_other_host = (host_t* (*)(ike_sa_t*)) get_other_host; this->public.set_other_host = (void (*)(ike_sa_t*,host_t*)) set_other_host; + this->public.update_hosts = (void(*)(ike_sa_t*, host_t *me, host_t *other))update_hosts; this->public.get_my_id = (identification_t* (*)(ike_sa_t*)) get_my_id; this->public.set_my_id = (void (*)(ike_sa_t*,identification_t*)) set_my_id; this->public.get_other_id = (identification_t* (*)(ike_sa_t*)) get_other_id; this->public.set_other_id = (void (*)(ike_sa_t*,identification_t*)) set_other_id; this->public.get_other_ca = (ca_info_t* (*)(ike_sa_t*)) get_other_ca; this->public.set_other_ca = (void (*)(ike_sa_t*,ca_info_t*)) set_other_ca; + this->public.enable_extension = (void(*)(ike_sa_t*, ike_extension_t extension))enable_extension; + this->public.supports_extension = (bool(*)(ike_sa_t*, ike_extension_t extension))supports_extension; + this->public.set_condition = (void (*)(ike_sa_t*, ike_condition_t,bool)) set_condition; + this->public.has_condition = (bool (*)(ike_sa_t*,ike_condition_t)) has_condition; + this->public.set_pending_updates = (void(*)(ike_sa_t*, u_int32_t updates))set_pending_updates; + this->public.get_pending_updates = (u_int32_t(*)(ike_sa_t*))get_pending_updates; + this->public.create_additional_address_iterator = (iterator_t*(*)(ike_sa_t*))create_additional_address_iterator; + this->public.add_additional_address = (void(*)(ike_sa_t*, host_t *host))add_additional_address; this->public.retransmit = (status_t (*)(ike_sa_t *, u_int32_t)) retransmit; this->public.delete = (status_t (*)(ike_sa_t*))delete_; this->public.destroy = (void (*)(ike_sa_t*))destroy; @@ -1927,10 +2067,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.rekey_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa; this->public.delete_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa; this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa; - this->public.enable_natt = (void (*)(ike_sa_t*, bool)) enable_natt; - this->public.is_natt_enabled = (bool (*)(ike_sa_t*)) is_natt_enabled; this->public.rekey = (status_t (*)(ike_sa_t*))rekey; - this->public.reestablish = (void (*)(ike_sa_t*))reestablish; + this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish; + 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; this->public.reset = (void (*)(ike_sa_t*))reset; @@ -1947,6 +2086,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->other_ca = NULL; + this->extensions = 0; + this->conditions = 0; this->crypter_in = NULL; this->crypter_out = NULL; this->signer_in = NULL; @@ -1955,8 +2096,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->skp_verify = chunk_empty; this->skp_build = chunk_empty; this->child_prf = NULL; - this->nat_here = FALSE; - this->nat_there = FALSE; this->state = IKE_CREATED; this->time.inbound = this->time.outbound = time(NULL); this->time.established = 0; @@ -1969,6 +2108,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->my_virtual_ip = NULL; this->other_virtual_ip = NULL; this->dns_servers = linked_list_create(); + this->additional_addresses = linked_list_create(); + this->pending_updates = 0; this->keyingtry = 0; return &this->public; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 76942b208..ba189577c 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -25,6 +25,8 @@ #ifndef IKE_SA_H_ #define IKE_SA_H_ +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 struct ike_sa_t ike_sa_t; @@ -70,6 +72,47 @@ typedef struct ike_sa_t ike_sa_t; */ #define RETRY_JITTER 20 +/** + * @brief Extensions (or optional features) the peer supports + */ +enum ike_extension_t { + + /** + * peer supports NAT traversal as specified in RFC4306 + */ + EXT_NATT = (1<<0), + + /** + * peer supports MOBIKE (RFC4555) + */ + EXT_MOBIKE = (1<<1), +}; + +/** + * @brief Conditions of an IKE_SA, change during its lifetime + */ +enum ike_condition_t { + + /** + * Connection is natted somewhere + */ + COND_NAT_ANY = (1<<0), + + /** + * we are behind NAT + */ + COND_NAT_HERE = (1<<1), + + /** + * other is behind NAT + */ + COND_NAT_THERE = (1<<2), + + /** + * peer is currently not reachable (due missing route, ...) + */ + COND_STALE = (1<<3), +}; /** * @brief State of an IKE_SA. @@ -240,6 +283,17 @@ struct ike_sa_t { void (*set_other_host) (ike_sa_t *this, host_t *other); /** + * @brief Update the IKE_SAs host. + * + * Hosts may be NULL to use current host. + * + * @param this calling object + * @param me new local host address, or NULL + * @param other new remote host address, or NULL + */ + void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other); + + /** * @brief Get the own identification. * * @param this calling object @@ -318,8 +372,83 @@ struct ike_sa_t { * @param config peer_config to use */ void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config); + + /** + * @brief Add an additional address for the peer. + * + * In MOBIKE, a peer may transmit additional addresses where it is + * reachable. These are stored in the IKE_SA. + * The own list of addresses is not stored, they are queried from + * the kernel when required. + * + * @param this calling object + * @param host host to add to list + */ + void (*add_additional_address)(ike_sa_t *this, host_t *host); + + /** + * @brief Create an iterator over all additional addresses of the peer. + * + * @param this calling object + * @return iterator over addresses + */ + iterator_t* (*create_additional_address_iterator)(ike_sa_t *this); + + /** + * @brief Enable an extension the peer supports. + * + * If support for an IKE extension is detected, this method is called + * to enable that extension and behave accordingly. + * + * @param this calling object + * @param extension extension to enable + */ + void (*enable_extension)(ike_sa_t *this, ike_extension_t extension); + + /** + * @brief Check if the peer supports an extension. + * + * @param this calling object + * @param extension extension to check for support + * @return TRUE if peer supports it, FALSE otherwise + */ + bool (*supports_extension)(ike_sa_t *this, ike_extension_t extension); + + /** + * @brief Enable/disable a condition flag for this IKE_SA. + * + * @param this calling object + * @param condition condition to enable/disable + * @param enable TRUE to enable condition, FALSE to disable + */ + void (*set_condition) (ike_sa_t *this, ike_condition_t condition, bool enable); /** + * @brief Check if a condition flag is set. + * + * @param this calling object + * @param condition condition to check + * @return TRUE if condition flag set, FALSE otherwise + */ + bool (*has_condition) (ike_sa_t *this, ike_condition_t condition); + + /** + * @brief Get the number of queued MOBIKE address updates. + * + * @param this calling object + * @return number of pending updates + */ + u_int32_t (*get_pending_updates)(ike_sa_t *this); + + /** + * @brief Set the number of queued MOBIKE address updates. + * + * @param this calling object + * @param updates number of pending updates + */ + void (*set_pending_updates)(ike_sa_t *this, u_int32_t updates); + + /** * @brief Initiate a new connection. * * The configs are owned by the IKE_SA after the call. @@ -389,6 +518,21 @@ struct ike_sa_t { status_t (*delete) (ike_sa_t *this); /** + * @brief Update IKE_SAs after network interfaces have changed. + * + * Whenever the network interface configuration changes, the kernel + * interface calls roam() on each IKE_SA. The IKE_SA then checks if + * the new network config requires changes, and handles appropriate. + * If MOBIKE is supported, addresses are updated; If not, the tunnel is + * restarted. + * + * @param this calling object + * @param address TRUE if address list changed, FALSE otherwise + * @return SUCCESS, FAILED, DESTROY_ME + */ + status_t (*roam)(ike_sa_t *this, bool address); + + /** * @brief Processes a incoming IKEv2-Message. * * Message processing may fail. If a critical failure occurs, @@ -457,29 +601,6 @@ struct ike_sa_t { * @param this calling object */ void (*send_keepalive) (ike_sa_t *this); - - /** - * @brief Check if NAT traversal is enabled for this IKE_SA. - * - * @param this calling object - * @return TRUE if NAT traversal enabled - */ - bool (*is_natt_enabled) (ike_sa_t *this); - - /** - * @brief Enable NAT detection for this IKE_SA. - * - * If a Network address translation is detected with - * NAT_DETECTION notifys, a SA must switch to ports - * 4500. To enable this behavior, call enable_natt(). - * It is relevant which peer is NATted, this is specified - * with the "local" parameter. Call it twice when both - * are NATted. - * - * @param this calling object - * @param local TRUE, if we are NATted, FALSE if other - */ - void (*enable_natt) (ike_sa_t *this, bool local); /** * @brief Derive all keys and create the transforms for IKE communication. @@ -621,11 +742,12 @@ struct ike_sa_t { * @brief Restablish the IKE_SA. * * Create a completely new IKE_SA with authentication, recreates all children - * within the IKE_SA, but lets the old IKE_SA untouched. + * within the IKE_SA, closes this IKE_SA. * * @param this calling object + * @return DESTROY_ME to destroy the IKE_SA */ - void (*reestablish) (ike_sa_t *this); + status_t (*reestablish) (ike_sa_t *this); /** * @brief Set the virtual IP to use for this IKE_SA and its children. diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index a62ec5e3c..56b865891 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -525,19 +525,21 @@ static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this, /* IKE_SA has no IDs yet, so we can't use it */ continue; } - + DBG2(DBG_MGR, "candidate IKE_SA for \n\t%H[%D]...%H[%D]\n\t%H[%D]...%H[%D]", + my_host, my_id, other_host, other_id, + found_my_host, found_my_id, found_other_host, found_other_id); /* compare ID and hosts. Supplied ID may contain wildcards, and IP * may be %any. */ - if ((found_my_host->is_anyaddr(found_my_host) || + if ((my_host->is_anyaddr(my_host) || my_host->ip_equals(my_host, found_my_host)) && - (found_other_host->is_anyaddr(found_other_host) || + (other_host->is_anyaddr(other_host) || other_host->ip_equals(other_host, found_other_host)) && found_my_id->matches(found_my_id, my_id, &wc) && found_other_id->matches(found_other_id, other_id, &wc)) { /* looks good, we take this one */ DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]", - my_host, other_host, my_id, other_id); + my_host, my_id, other_host, other_id); entry->checked_out = TRUE; ike_sa = entry->ike_sa; } @@ -682,16 +684,16 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name, /** * Iterator hook for iterate, gets ike_sas instead of entries */ -static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in, - ike_sa_t **out) +static hook_result_t iterator_hook(private_ike_sa_manager_t* this, entry_t *in, + ike_sa_t **out) { /* check out entry */ if (wait_for_entry(this, in)) { *out = in->ike_sa; - return TRUE; + return HOOK_NEXT; } - return FALSE; + return HOOK_SKIP; } /** @@ -701,6 +703,7 @@ static iterator_t *create_iterator(private_ike_sa_manager_t* this) { iterator_t *iterator = this->ike_sa_list->create_iterator_locked( this->ike_sa_list, &this->mutex); + /* register hook to iterator over ike_sas, not entries */ iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this); return iterator; diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index e67508ed1..55592f437 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -27,6 +27,7 @@ #include <daemon.h> #include <sa/tasks/ike_init.h> #include <sa/tasks/ike_natd.h> +#include <sa/tasks/ike_mobike.h> #include <sa/tasks/ike_auth.h> #include <sa/tasks/ike_cert.h> #include <sa/tasks/ike_rekey.h> @@ -130,6 +131,11 @@ struct private_task_manager_t { * List of tasks initiated by peer */ linked_list_t *passive_tasks; + + /** + * the task manager has been reset + */ + bool reset; }; /** @@ -140,7 +146,7 @@ static void flush(private_task_manager_t *this) task_t *task; this->queued_tasks->destroy_offset(this->queued_tasks, - offsetof(task_t, destroy)); + offsetof(task_t, destroy)); this->passive_tasks->destroy_offset(this->passive_tasks, offsetof(task_t, destroy)); @@ -235,7 +241,7 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id) this->initiating.packet->clone(this->initiating.packet)); job = (job_t*)retransmit_job_create(this->initiating.mid, this->ike_sa->get_id(this->ike_sa)); - charon->event_queue->add_relative(charon->event_queue, job, timeout); + charon->scheduler->schedule_job(charon->scheduler, job, timeout); } return SUCCESS; } @@ -274,6 +280,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_MOBIKE); } break; case IKE_ESTABLISHED: @@ -302,7 +309,17 @@ static status_t build_request(private_task_manager_t *this) exchange = CREATE_CHILD_SA; break; } - if (activate_task(this, IKE_DEADPEER)) + if (activate_task(this, IKE_REAUTH)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, IKE_MOBIKE)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, IKE_DPD)) { exchange = INFORMATIONAL; break; @@ -338,6 +355,8 @@ static status_t build_request(private_task_manager_t *this) case IKE_REKEY: exchange = CREATE_CHILD_SA; break; + case IKE_MOBIKE: + exchange = INFORMATIONAL; default: continue; } @@ -415,6 +434,8 @@ static status_t process_response(private_task_manager_t *this, return DESTROY_ME; } + /* catch if we get resetted while processing */ + this->reset = FALSE; iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); while (iterator->iterate(iterator, (void*)&task)) { @@ -434,6 +455,12 @@ static status_t process_response(private_task_manager_t *this, iterator->destroy(iterator); return DESTROY_ME; } + if (this->reset) + { /* start all over again if we were reset */ + this->reset = FALSE; + iterator->destroy(iterator); + return build_request(this); + } } iterator->destroy(iterator); @@ -456,7 +483,7 @@ static void handle_collisions(private_task_manager_t *this, task_t *task) /* do we have to check */ if (type == IKE_REKEY || type == CHILD_REKEY || - type == CHILD_DELETE || type == IKE_DELETE) + type == CHILD_DELETE || type == IKE_DELETE || type == IKE_REAUTH) { /* find an exchange collision, and notify these tasks */ iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); @@ -465,7 +492,8 @@ static void handle_collisions(private_task_manager_t *this, task_t *task) switch (active->get_type(active)) { case IKE_REKEY: - if (type == IKE_REKEY || type == IKE_DELETE) + if (type == IKE_REKEY || type == IKE_DELETE || + type == IKE_REAUTH) { ike_rekey_t *rekey = (ike_rekey_t*)active; rekey->collide(rekey, task); @@ -571,6 +599,7 @@ static status_t process_request(private_task_manager_t *this, exchange_type_t exchange; payload_t *payload; notify_payload_t *notify; + delete_payload_t *delete; exchange = message->get_exchange_type(message); @@ -591,6 +620,8 @@ static status_t process_request(private_task_manager_t *this, 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_mobike_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); break; } case CREATE_CHILD_SA: @@ -646,27 +677,60 @@ static status_t process_request(private_task_manager_t *this, } case INFORMATIONAL: { - delete_payload_t *delete; - - delete = (delete_payload_t*)message->get_payload(message, DELETE); - if (delete) + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) { - if (delete->get_protocol_id(delete) == PROTO_IKE) + switch (payload->get_type(payload)) { - task = (task_t*)ike_delete_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + case NOTIFY: + { + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case ADDITIONAL_IP4_ADDRESS: + case ADDITIONAL_IP6_ADDRESS: + case NO_ADDITIONAL_ADDRESSES: + case UPDATE_SA_ADDRESSES: + case NO_NATS_ALLOWED: + case UNACCEPTABLE_ADDRESSES: + case UNEXPECTED_NAT_DETECTED: + case COOKIE2: + task = (task_t*)ike_mobike_create(this->ike_sa, + FALSE); + break; + default: + break; + } + break; + } + case DELETE: + { + delete = (delete_payload_t*)payload; + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + task = (task_t*)ike_delete_create(this->ike_sa, FALSE); + } + else + { + task = (task_t*)child_delete_create(this->ike_sa, NULL); + } + break; + } + default: + break; } - else + if (task) { - task = (task_t*)child_delete_create(this->ike_sa, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); + break; } } - else + iterator->destroy(iterator); + + if (task == NULL) { task = (task_t*)ike_dpd_create(FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); } + this->passive_tasks->insert_last(this->passive_tasks, task); break; } default: @@ -806,7 +870,7 @@ static void reset(private_task_manager_t *this) this->responding.packet = NULL; this->initiating.packet = NULL; this->responding.mid = 0; - this->initiating.mid = -1; + this->initiating.mid = 0; this->initiating.type = EXCHANGE_TYPE_UNDEFINED; /* reset active tasks */ @@ -816,6 +880,8 @@ static void reset(private_task_manager_t *this) task->migrate(task, this->ike_sa); this->queued_tasks->insert_first(this->queued_tasks, task); } + + this->reset = TRUE; } /** @@ -859,6 +925,7 @@ task_manager_t *task_manager_create(ike_sa_t *ike_sa) this->queued_tasks = linked_list_create(); this->active_tasks = linked_list_create(); this->passive_tasks = linked_list_create(); + this->reset = FALSE; return &this->public; } diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index f70730b05..42f34a94b 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -297,7 +297,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) this->mode = MODE_TUNNEL; DBG1(DBG_IKE, "not using tranport mode, not host-to-host"); } - else if (this->ike_sa->is_natt_enabled(this->ike_sa)) + else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) { this->mode = MODE_TUNNEL; DBG1(DBG_IKE, "not using tranport mode, connection NATed"); @@ -493,6 +493,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) static status_t build_i(private_child_create_t *this, message_t *message) { host_t *me, *other, *vip; + bool propose_all = FALSE; peer_cfg_t *peer_cfg; switch (message->get_exchange_type(message)) @@ -523,33 +524,53 @@ static status_t build_i(private_child_create_t *this, message_t *message) SIG(CHILD_UP_START, "establishing CHILD_SA"); - me = this->ike_sa->get_my_host(this->ike_sa); - other = this->ike_sa->get_other_host(this->ike_sa); - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = peer_cfg->get_my_virtual_ip(peer_cfg); + /* reuse virtual IP if we already have one */ + me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (me == NULL) + { + me = this->ike_sa->get_my_host(this->ike_sa); + } + other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); + if (other == NULL) + { + other = this->ike_sa->get_other_host(this->ike_sa); + } - if (vip) + /* check if we want a virtual IP, but don't have one */ + if (!this->reqid) + { + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + vip = peer_cfg->get_my_virtual_ip(peer_cfg); + if (vip) + { + propose_all = TRUE; + vip->destroy(vip); + } + } + + if (propose_all) { /* propose a 0.0.0.0/0 subnet when we use virtual ip */ this->tsi = this->config->get_traffic_selectors(this->config, TRUE, NULL, NULL); - vip->destroy(vip); } else - { /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */ + { /* but shorten a 0.0.0.0/0 subnet for host2host/we already have a vip */ this->tsi = this->config->get_traffic_selectors(this->config, TRUE, NULL, me); } this->tsr = this->config->get_traffic_selectors(this->config, FALSE, NULL, other); + this->proposals = this->config->get_proposals(this->config, this->dh_group == MODP_NONE); this->mode = this->config->get_mode(this->config); - this->child_sa = child_sa_create(me, other, - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->config, this->reqid, - this->ike_sa->is_natt_enabled(this->ike_sa)); + this->child_sa = child_sa_create( + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid, + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS) { @@ -609,9 +630,21 @@ static status_t process_r(private_child_create_t *this, message_t *message) peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); if (peer_cfg) { - this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, this->tsi, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); + host_t *me, *other; + + me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (me == NULL) + { + me = this->ike_sa->get_my_host(this->ike_sa); + } + other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); + if (other == NULL) + { + other = this->ike_sa->get_other_host(this->ike_sa); + } + + this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, + this->tsi, me, other); } return NEED_MORE; } @@ -660,12 +693,12 @@ static status_t build_r(private_child_create_t *this, message_t *message) return SUCCESS; } - this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->config, this->reqid, - this->ike_sa->is_natt_enabled(this->ike_sa)); + this->child_sa = child_sa_create( + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid, + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); switch (select_and_install(this, no_dh)) { diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 4f3c69034..3667d8fad 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -206,7 +206,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) DBG1(DBG_IKE, "CHILD_SA rekeying failed, " "trying again in %d seconds", retry); this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - charon->event_queue->add_relative(charon->event_queue, job, retry * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, retry * 1000); } return SUCCESS; } diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index d0dd49aee..c1c0cd5a2 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -636,7 +636,12 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) case INVALID_SELECTORS: /* these are errors, but are not critical as only the * CHILD_SA won't get build, but IKE_SA establishes anyway */ - break; + break; + case MOBIKE_SUPPORTED: + case ADDITIONAL_IP4_ADDRESS: + case ADDITIONAL_IP6_ADDRESS: + /* handled in ike_mobike task */ + break; default: { if (type < 16383) diff --git a/src/charon/sa/tasks/ike_dpd.c b/src/charon/sa/tasks/ike_dpd.c index 1cb05c45c..be751766e 100644 --- a/src/charon/sa/tasks/ike_dpd.c +++ b/src/charon/sa/tasks/ike_dpd.c @@ -61,7 +61,7 @@ static status_t return_success(private_ike_dpd_t *this, message_t *message) */ static task_type_t get_type(private_ike_dpd_t *this) { - return IKE_DEADPEER; + return IKE_DPD; } /** diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c new file mode 100644 index 000000000..8d4dce36c --- /dev/null +++ b/src/charon/sa/tasks/ike_mobike.c @@ -0,0 +1,431 @@ +/** + * @file ike_mobike.c + * + * @brief Implementation of the ike_mobike 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_mobike.h" + +#include <string.h> + +#include <daemon.h> +#include <sa/tasks/ike_natd.h> +#include <encoding/payloads/notify_payload.h> + + +typedef struct private_ike_mobike_t private_ike_mobike_t; + +/** + * Private members of a ike_mobike_t task. + */ +struct private_ike_mobike_t { + + /** + * Public methods and task_t interface. + */ + ike_mobike_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * cookie2 value to verify new addresses + */ + chunk_t cookie2; + + /** + * NAT discovery reusing the IKE_NATD task + */ + ike_natd_t *natd; + + /** + * use task to update addresses + */ + bool roam; + + /** + * include address list update + */ + bool address; +}; + +/** + * flush the IKE_SAs list of additional addresses + */ +static void flush_additional_addresses(private_ike_mobike_t *this) +{ + iterator_t *iterator; + host_t *host; + + iterator = this->ike_sa->create_additional_address_iterator(this->ike_sa); + while (iterator->iterate(iterator, (void**)&host)) + { + iterator->remove(iterator); + host->destroy(host); + } + iterator->destroy(iterator); +} + + +/** + * read notifys from message and evaluate them + */ +static void process_payloads(private_ike_mobike_t *this, message_t *message) +{ + iterator_t *iterator; + payload_t *payload; + bool first = TRUE; + + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) + { + int family = AF_INET; + notify_payload_t *notify; + chunk_t data; + host_t *host; + + if (payload->get_type(payload) != NOTIFY) + { + continue; + } + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case MOBIKE_SUPPORTED: + { + DBG1(DBG_IKE, "peer supports MOBIKE"); + this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE); + break; + } + case ADDITIONAL_IP6_ADDRESS: + { + family = AF_INET6; + /* fall through */ + } + case ADDITIONAL_IP4_ADDRESS: + { + if (first) + { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */ + flush_additional_addresses(this); + first = FALSE; + } + data = notify->get_notification_data(notify); + host = host_create_from_chunk(family, data, 0); + DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host); + this->ike_sa->add_additional_address(this->ike_sa, host); + break; + } + case UPDATE_SA_ADDRESSES: + { + this->roam = TRUE; + break; + } + case NO_ADDITIONAL_ADDRESSES: + { + flush_additional_addresses(this); + break; + } + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: + { + /* NAT check in this MOBIKE exchange, create subtask for it */ + if (this->natd == NULL) + { + this->natd = ike_natd_create(this->ike_sa, this->initiator); + } + break; + } + default: + break; + } + } + iterator->destroy(iterator); +} + +/** + * Add ADDITIONAL_*_ADDRESS notifys depending on our address list + */ +static void build_address_list(private_ike_mobike_t *this, message_t *message) +{ + iterator_t *iterator; + host_t *host, *me; + notify_type_t type; + bool additional = FALSE; + + me = this->ike_sa->get_my_host(this->ike_sa); + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + while (iterator->iterate(iterator, (void**)&host)) + { + if (me->ip_equals(me, host)) + { /* "ADDITIONAL" means do not include IKE_SAs host */ + continue; + } + switch (host->get_family(host)) + { + case AF_INET: + type = ADDITIONAL_IP4_ADDRESS; + break; + case AF_INET6: + type = ADDITIONAL_IP6_ADDRESS; + break; + default: + continue; + } + message->add_notify(message, FALSE, type, host->get_address(host)); + additional = TRUE; + } + if (!additional) + { + message->add_notify(message, FALSE, NO_ADDITIONAL_ADDRESSES, chunk_empty); + } + iterator->destroy(iterator); +} + +/** + * update addresses of associated CHILD_SAs + */ +static void update_children(private_ike_mobike_t *this) +{ + iterator_t *iterator; + child_sa_t *child_sa; + + iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); + while (iterator->iterate(iterator, (void**)&child_sa)) + { + child_sa->update_hosts(child_sa, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); + } + iterator->destroy(iterator); +} + +/** + * Implementation of task_t.process for initiator + */ +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->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); + build_address_list(this, message); + } + else + { + if (this->roam) + { + message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty); + } + if (this->address) + { + build_address_list(this, message); + } + + this->natd = ike_natd_create(this->ike_sa, this->initiator); + this->natd->task.build(&this->natd->task, message); + update_children(this); + } + + return NEED_MORE; +} + +/** + * Implementation of task_t.process for responder + */ +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)) + { + process_payloads(this, message); + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + process_payloads(this, message); + if (this->roam) + { + host_t *me, *other; + + me = message->get_destination(message); + other = message->get_source(message); + this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + } + + if (this->natd) + { + this->natd->task.process(&this->natd->task, message); + } + } + return NEED_MORE; +} + +/** + * Implementation of task_t.build for responder + */ +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)) + { + if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) + { + message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); + build_address_list(this, message); + } + return SUCCESS; + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + if (this->natd) + { + this->natd->task.build(&this->natd->task, message); + } + if (this->roam) + { + update_children(this); + } + return SUCCESS; + } + return NEED_MORE; +} + +/** + * Implementation of task_t.process for initiator + */ +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)) + { + process_payloads(this, message); + + return SUCCESS; + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + u_int32_t updates = this->ike_sa->get_pending_updates(this->ike_sa) - 1; + this->ike_sa->set_pending_updates(this->ike_sa, updates); + if (updates > 0) + { + /* newer update queued, ignore this one */ + return SUCCESS; + } + process_payloads(this, message); + if (this->natd) + { + this->natd->task.process(&this->natd->task, message); + } + if (this->roam) + { + /* update again, as NAT state may have changed */ + update_children(this); + } + return SUCCESS; + } + return NEED_MORE; +} + +/** + * Implementation of ike_mobike_t.roam. + */ +static void roam(private_ike_mobike_t *this, bool address) +{ + this->roam = TRUE; + this->address = address; + this->ike_sa->set_pending_updates(this->ike_sa, + this->ike_sa->get_pending_updates(this->ike_sa) + 1); +} + +/** + * Implementation of task_t.get_type + */ +static task_type_t get_type(private_ike_mobike_t *this) +{ + return IKE_MOBIKE; +} + +/** + * Implementation of task_t.migrate + */ +static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa) +{ + chunk_free(&this->cookie2); + this->ike_sa = ike_sa; + if (this->natd) + { + this->natd->task.migrate(&this->natd->task, ike_sa); + } +} + +/** + * Implementation of task_t.destroy + */ +static void destroy(private_ike_mobike_t *this) +{ + chunk_free(&this->cookie2); + if (this->natd) + { + this->natd->task.destroy(&this->natd->task); + } + free(this); +} + +/* + * Described in header. + */ +ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_mobike_t *this = malloc_thing(private_ike_mobike_t); + + this->public.roam = (void(*)(ike_mobike_t*,bool))roam; + 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; + this->initiator = initiator; + this->roam = FALSE; + this->address = TRUE; + this->cookie2 = chunk_empty; + this->natd = NULL; + + return &this->public; +} + diff --git a/src/charon/sa/tasks/ike_mobike.h b/src/charon/sa/tasks/ike_mobike.h new file mode 100644 index 000000000..db493c459 --- /dev/null +++ b/src/charon/sa/tasks/ike_mobike.h @@ -0,0 +1,73 @@ +/** + * @file ike_mobike.h + * + * @brief Interface ike_mobike_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_MOBIKE_H_ +#define IKE_MOBIKE_H_ + +typedef struct ike_mobike_t ike_mobike_t; + +#include <library.h> +#include <sa/ike_sa.h> +#include <sa/tasks/task.h> + +/** + * @brief Task of type ike_mobike, detects and handles MOBIKE extension. + * + * The MOBIKE extension is defined in RFC4555. It allows to update IKE + * and IPsec tunnel addresses. + * This tasks handles the MOBIKE_SUPPORTED notify exchange to detect MOBIKE + * support, allows the exchange of ADDITIONAL_*_ADDRESS to exchange additional + * endpoints and handles the UPDATE_SA_ADDRESS notify to finally update + * endpoints. + * + * @b Constructors: + * - ike_mobike_create() + * + * @ingroup tasks + */ +struct ike_mobike_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * @brief Use the task to roam to other addresses. + * + * @param this calling object + * @param address TRUE to include address list update + */ + void (*roam)(ike_mobike_t *this, bool address); +}; + +/** + * @brief Create a new ike_mobike task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if taks is initiated by us + * @return ike_mobike task to handle by the task_manager + */ +ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator); + +#endif /* IKE_MOBIKE_H_ */ + diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index 50b5d652b..84a28d024 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -203,14 +203,12 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) if (this->src_seen && this->dst_seen) { - if (!this->dst_matched) - { - this->ike_sa->enable_natt(this->ike_sa, TRUE); - } - if (!this->src_matched) - { - this->ike_sa->enable_natt(this->ike_sa, FALSE); - } + this->ike_sa->enable_extension(this->ike_sa, EXT_NATT); + + this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, + !this->dst_matched); + this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, + !this->src_matched); } } @@ -220,8 +218,11 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) static status_t process_i(private_ike_natd_t *this, message_t *message) { process_payloads(this, message); - - if (this->ike_sa->is_natt_enabled(this->ike_sa)) + + /* if peer supports NAT-T, we switch to port 4500 even + * if no NAT is detected. MOBIKE requires this. */ + if (message->get_exchange_type(message) == IKE_SA_INIT && + this->ike_sa->supports_extension(this->ike_sa, EXT_NATT)) { host_t *me, *other; @@ -240,33 +241,49 @@ static status_t process_i(private_ike_natd_t *this, message_t *message) static status_t build_i(private_ike_natd_t *this, message_t *message) { notify_payload_t *notify; - linked_list_t *list; + iterator_t *iterator; host_t *host; - /* include one notify if our address is defined, all addresses otherwise */ + /* destination is always set */ + host = this->ike_sa->get_other_host(this->ike_sa); + notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); + message->add_payload(message, (payload_t*)notify); + + /* source may be any, we have 3 possibilities to get our source address: + * 1. It is defined in the config => use the one of the IKE_SA + * 2. We do a routing lookup in the kernel interface + * 3. Include all possbile addresses + */ host = this->ike_sa->get_my_host(this->ike_sa); - if (host->is_anyaddr(host)) + if (!host->is_anyaddr(host)) + { /* 1. */ + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + message->add_payload(message, (payload_t*)notify); + } + else { - /* TODO: we could get the src address from netlink!? */ - list = charon->kernel_interface->create_address_list(charon->kernel_interface); - while (list->remove_first(list, (void**)&host) == SUCCESS) - { + host = charon->kernel_interface->get_source_addr( + charon->kernel_interface, + this->ike_sa->get_other_host(this->ike_sa)); + if (host) + { /* 2. */ + host->set_port(host, IKEV2_UDP_PORT); notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - host->destroy(host); message->add_payload(message, (payload_t*)notify); + host->destroy(host); + } + else + { /* 3. */ + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + while (iterator->iterate(iterator, (void**)&host)) + { + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + message->add_payload(message, (payload_t*)notify); + } + iterator->destroy(iterator); } - list->destroy(list); - } - else - { - notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - message->add_payload(message, (payload_t*)notify); } - - host = this->ike_sa->get_other_host(this->ike_sa); - notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); - message->add_payload(message, (payload_t*)notify); - return NEED_MORE; } @@ -279,7 +296,8 @@ static status_t build_r(private_ike_natd_t *this, message_t *message) host_t *me, *other; /* only add notifies on successfull responses. */ - if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) + if (message->get_exchange_type(message) == IKE_SA_INIT && + message->get_payload(message, SECURITY_ASSOCIATION) == NULL) { return SUCCESS; } diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c new file mode 100644 index 000000000..0e98382a8 --- /dev/null +++ b/src/charon/sa/tasks/ike_reauth.c @@ -0,0 +1,175 @@ +/** + * @file ike_reauth.c + * + * @brief Implementation of the ike_reauth task. + * + */ + +/* + * Copyright (C) 2006-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_reauth.h" + +#include <daemon.h> +#include <sa/tasks/ike_delete.h> + + +typedef struct private_ike_reauth_t private_ike_reauth_t; + +/** + * Private members of a ike_reauth_t task. + */ +struct private_ike_reauth_t { + + /** + * Public methods and task_t interface. + */ + ike_reauth_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * reused ike_delete task + */ + ike_delete_t *ike_delete; +}; + +/** + * Implementation of task_t.build for initiator + */ +static status_t build_i(private_ike_reauth_t *this, message_t *message) +{ + return this->ike_delete->task.build(&this->ike_delete->task, message); +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t process_i(private_ike_reauth_t *this, message_t *message) +{ + ike_sa_t *new; + host_t *host; + iterator_t *iterator; + child_sa_t *child_sa; + + /* process delete response first */ + this->ike_delete->task.process(&this->ike_delete->task, message); + + /* reestablish only if we have children */ + iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); + if (iterator->get_count(iterator) == 0) + { + DBG1(DBG_IKE, "unable to reestablish IKE_SA, no CHILD_SA to recreate"); + iterator->destroy(iterator); + return FAILED; + } + + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE); + + new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa)); + host = this->ike_sa->get_other_host(this->ike_sa); + new->set_other_host(new, host->clone(host)); + host = this->ike_sa->get_my_host(this->ike_sa); + new->set_my_host(new, host->clone(host)); + /* if we already have a virtual IP, we reuse it */ + host = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (host) + { + new->set_virtual_ip(new, TRUE, host); + } + + while (iterator->iterate(iterator, (void**)&child_sa)) + { + switch (child_sa->get_state(child_sa)) + { + case CHILD_ROUTED: + { + /* move routed child directly */ + iterator->remove(iterator); + new->add_child_sa(new, child_sa); + break; + } + default: + { + /* initiate/queue all child SAs */ + child_cfg_t *child_cfg = child_sa->get_config(child_sa); + child_cfg->get_ref(child_cfg); + if (new->initiate(new, child_cfg) == DESTROY_ME) + { + iterator->destroy(iterator); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, new); + DBG1(DBG_IKE, "reestablishing IKE_SA failed"); + return FAILED; + } + break; + } + } + } + iterator->destroy(iterator); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); + + /* we always return failed to delete the obsolete IKE_SA */ + return FAILED; +} + +/** + * Implementation of task_t.get_type + */ +static task_type_t get_type(private_ike_reauth_t *this) +{ + return IKE_REAUTH; +} + +/** + * Implementation of task_t.migrate + */ +static void migrate(private_ike_reauth_t *this, ike_sa_t *ike_sa) +{ + this->ike_delete->task.migrate(&this->ike_delete->task, ike_sa); + this->ike_sa = ike_sa; +} + +/** + * Implementation of task_t.destroy + */ +static void destroy(private_ike_reauth_t *this) +{ + this->ike_delete->task.destroy(&this->ike_delete->task); + free(this); +} + +/* + * Described in header. + */ +ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa) +{ + private_ike_reauth_t *this = malloc_thing(private_ike_reauth_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; + this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + + this->ike_sa = ike_sa; + this->ike_delete = ike_delete_create(ike_sa, TRUE); + + return &this->public; +} + diff --git a/src/charon/sa/tasks/ike_reauth.h b/src/charon/sa/tasks/ike_reauth.h new file mode 100644 index 000000000..3c872e1e1 --- /dev/null +++ b/src/charon/sa/tasks/ike_reauth.h @@ -0,0 +1,59 @@ +/** + * @file ike_reauth.h + * + * @brief Interface ike_reauth_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_REAUTH_H_ +#define IKE_REAUTH_H_ + +typedef struct ike_reauth_t ike_reauth_t; + +#include <library.h> +#include <sa/ike_sa.h> +#include <sa/tasks/task.h> + +/** + * @brief Task of type ike_reauth, reestablishes an IKE_SA. + * + * @b Constructors: + * - ike_reauth_create() + * + * @ingroup tasks + */ +struct ike_reauth_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * @brief Create a new ike_reauth task. + * + * This task is initiator only. + * + * @param ike_sa IKE_SA this task works for + * @return ike_reauth task to handle by the task_manager + */ +ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa); + +#endif /* IKE_REAUTH_H_ */ + diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index d54fc3524..827f95156 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -170,8 +170,9 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) { case FAILED: /* rekeying failed, fallback to old SA */ - if (!(this->collision && - this->collision->get_type(this->collision) == IKE_DELETE)) + if (!(this->collision && ( + this->collision->get_type(this->collision) == IKE_DELETE || + this->collision->get_type(this->collision) == IKE_REAUTH))) { job_t *job; u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); @@ -180,7 +181,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) DBG1(DBG_IKE, "IKE_SA rekeying failed, " "trying again in %d seconds", retry); this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->event_queue->add_relative(charon->event_queue, job, retry * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, retry * 1000); } return SUCCESS; case NEED_MORE: @@ -231,7 +232,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) } job = (job_t*)delete_ike_sa_job_create(to_delete, TRUE); - charon->job_queue->add(charon->job_queue, job); + charon->processor->queue_job(charon->processor, job); return SUCCESS; } diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c index 68d8ebf0c..713403d47 100644 --- a/src/charon/sa/tasks/task.c +++ b/src/charon/sa/tasks/task.c @@ -25,14 +25,16 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY, "IKE_INIT", "IKE_NATD", + "IKE_MOBIKE", "IKE_AUTHENTICATE", "IKE_CERT", "IKE_CONFIG", - "IKE_DPD", "IKE_REKEY", + "IKE_REAUTH", "IKE_DELETE", - "IKE_DEADPEER", + "IKE_DPD", "CHILD_CREATE", "CHILD_DELETE", "CHILD_REKEY", ); + diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h index 128d7db4a..ff60ea816 100644 --- a/src/charon/sa/tasks/task.h +++ b/src/charon/sa/tasks/task.h @@ -40,16 +40,18 @@ enum task_type_t { IKE_INIT, /** detect NAT situation */ IKE_NATD, + /** handle MOBIKE stuff */ + IKE_MOBIKE, /** authenticate the initiated IKE_SA */ IKE_AUTHENTICATE, /** exchange certificates and requests */ IKE_CERT, /** Configuration payloads, virtual IP and such */ IKE_CONFIG, - /** DPD detection */ - IKE_DEADPEER, /** rekey an IKE_SA */ IKE_REKEY, + /** reestablish a complete IKE_SA */ + IKE_REAUTH, /** delete an IKE_SA */ IKE_DELETE, /** liveness check */ diff --git a/src/include/Makefile.in b/src/include/Makefile.in index 68477343f..7fb9ccb22 100644 --- a/src/include/Makefile.in +++ b/src/include/Makefile.in @@ -105,6 +105,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/ipsec/Makefile.in b/src/ipsec/Makefile.in index 3a12ba5b9..decd32b88 100644 --- a/src/ipsec/Makefile.in +++ b/src/ipsec/Makefile.in @@ -113,6 +113,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/ipsec/ipsec.in b/src/ipsec/ipsec.in index 067d24784..e4cedd09a 100755 --- a/src/ipsec/ipsec.in +++ b/src/ipsec/ipsec.in @@ -36,8 +36,7 @@ IPSEC_STARTER="${IPSEC_DIR}/starter" export IPSEC_DIR IPSEC_SBINDIR IPSEC_CONFDIR IPSEC_PIDDIR IPSEC_VERSION IPSEC_NAME IPSEC_STARTER_PID IPSEC_PLUTO_PID IPSEC_CHARON_PID -IPSEC_DISTRO="Institute for Internet Technologies and Applications\n - University of Applied Sciences Rapperswil, Switzerland" +IPSEC_DISTRO="Institute for Internet Technologies and Applications\nUniversity of Applied Sciences Rapperswil, Switzerland" case "$1" in '') @@ -82,10 +81,6 @@ case "$1" in echo "$IPSEC_VERSION" exit 0 ;; ---copyright) - set _copyright - # and fall through, invoking "ipsec _copyright" - ;; --directory) echo "$IPSEC_DIR" exit 0 @@ -94,6 +89,10 @@ case "$1" in echo "$IPSEC_CONFDIR" exit 0 ;; +copyright|--copyright) + set _copyright + # and fall through, invoking "ipsec _copyright" + ;; down) shift if [ "$#" -ne 1 ] @@ -266,8 +265,8 @@ update) ;; version|--version) echo "Linux $IPSEC_NAME $IPSEC_VERSION" + echo -e $IPSEC_DISTRO echo "See \`ipsec --copyright' for copyright information." - echo $IPSEC_DISTRO exit 0 ;; --*) diff --git a/src/libcrypto/Makefile.in b/src/libcrypto/Makefile.in index dca1b18e7..f46022521 100644 --- a/src/libcrypto/Makefile.in +++ b/src/libcrypto/Makefile.in @@ -131,6 +131,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/libfreeswan/Makefile.in b/src/libfreeswan/Makefile.in index fa57d5aab..9cb648d9d 100644 --- a/src/libfreeswan/Makefile.in +++ b/src/libfreeswan/Makefile.in @@ -144,6 +144,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/libfreeswan/copyright.c b/src/libfreeswan/copyright.c index 0e836f6c2..8796751fe 100644 --- a/src/libfreeswan/copyright.c +++ b/src/libfreeswan/copyright.c @@ -18,12 +18,12 @@ #include "freeswan.h" static const char *co[] = { - "Copyright (C) 1999-2005 Henry Spencer, Richard Guy Briggs,", + "Copyright (C) 1999-2007 Henry Spencer, Richard Guy Briggs,", " D. Hugh Redelmeier, Sandy Harris, Claudia Schmeing,", " Michael Richardson, Angelos D. Keromytis, John Ioannidis,", "", " Ken Bantoft, Stephen J. Bevan, JuanJo Ciarlante, Mathieu Lafon,", - " Stephane Laroche, Kai Martius, Tuomo Soini, Herbert Xu,", + " Stephane Laroche, Kai Martius, Stephan Scholz, Tuomo Soini, Herbert Xu,", "", " Andreas Steffen, Martin Berner, Marco Bertossa, David Buechi,", " Ueli Galizzi, Christoph Gysin, Andreas Hess, Patric Lichtsteiner,", @@ -31,7 +31,8 @@ static const char *co[] = { " Mario Strasser, Lukas Suter, Roger Wegmann, Simon Zwahlen,", " Zuercher Hochschule Winterthur (Switzerland).", "", - " Jan Hutter, Martin Willi, Andreas Steffen,", + " Tobias Brunner, Fabian Hartmann, Noah Heusser, Jan Hutter,", + " Daniel Röthlisberger, Martin Willi, Andreas Steffen,", " Hochschule fuer Technik Rapperswil (Switzerland).", "", "This program is free software; you can redistribute it and/or modify it", diff --git a/src/libstrongswan/Makefile.in b/src/libstrongswan/Makefile.in index 015308449..f1144144e 100644 --- a/src/libstrongswan/Makefile.in +++ b/src/libstrongswan/Makefile.in @@ -144,6 +144,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/libstrongswan/asn1/oid.c b/src/libstrongswan/asn1/oid.c index 48df1b7c4..6b16d5a64 100644 --- a/src/libstrongswan/asn1/oid.c +++ b/src/libstrongswan/asn1/oid.c @@ -62,137 +62,142 @@ const oid_t oid_names[] = { { 0x25, 50, 0, "extendedKeyUsage" }, /* 49 */ { 0x37, 51, 0, "targetInformation" }, /* 50 */ { 0x38, 0, 0, "noRevAvail" }, /* 51 */ - {0x2A, 89, 1, "" }, /* 52 */ + {0x2A, 94, 1, "" }, /* 52 */ { 0x86, 0, 1, "" }, /* 53 */ { 0x48, 0, 1, "" }, /* 54 */ { 0x86, 0, 1, "" }, /* 55 */ - { 0xF7, 0, 1, "" }, /* 56 */ - { 0x0D, 0, 1, "RSADSI" }, /* 57 */ - { 0x01, 84, 1, "PKCS" }, /* 58 */ - { 0x01, 67, 1, "PKCS-1" }, /* 59 */ - { 0x01, 61, 0, "rsaEncryption" }, /* 60 */ - { 0x02, 62, 0, "md2WithRSAEncryption" }, /* 61 */ - { 0x04, 63, 0, "md5WithRSAEncryption" }, /* 62 */ - { 0x05, 64, 0, "sha-1WithRSAEncryption" }, /* 63 */ - { 0x0B, 65, 0, "sha256WithRSAEncryption"}, /* 64 */ - { 0x0C, 66, 0, "sha384WithRSAEncryption"}, /* 65 */ - { 0x0D, 0, 0, "sha512WithRSAEncryption"}, /* 66 */ - { 0x07, 74, 1, "PKCS-7" }, /* 67 */ - { 0x01, 69, 0, "data" }, /* 68 */ - { 0x02, 70, 0, "signedData" }, /* 69 */ - { 0x03, 71, 0, "envelopedData" }, /* 70 */ - { 0x04, 72, 0, "signedAndEnvelopedData" }, /* 71 */ - { 0x05, 73, 0, "digestedData" }, /* 72 */ - { 0x06, 0, 0, "encryptedData" }, /* 73 */ - { 0x09, 0, 1, "PKCS-9" }, /* 74 */ - { 0x01, 76, 0, "E" }, /* 75 */ - { 0x02, 77, 0, "unstructuredName" }, /* 76 */ - { 0x03, 78, 0, "contentType" }, /* 77 */ - { 0x04, 79, 0, "messageDigest" }, /* 78 */ - { 0x05, 80, 0, "signingTime" }, /* 79 */ - { 0x06, 81, 0, "counterSignature" }, /* 80 */ - { 0x07, 82, 0, "challengePassword" }, /* 81 */ - { 0x08, 83, 0, "unstructuredAddress" }, /* 82 */ - { 0x0E, 0, 0, "extensionRequest" }, /* 83 */ - { 0x02, 87, 1, "digestAlgorithm" }, /* 84 */ - { 0x02, 86, 0, "md2" }, /* 85 */ - { 0x05, 0, 0, "md5" }, /* 86 */ - { 0x03, 0, 1, "encryptionAlgorithm" }, /* 87 */ - { 0x07, 0, 0, "3des-ede-cbc" }, /* 88 */ - {0x2B, 150, 1, "" }, /* 89 */ - { 0x06, 137, 1, "dod" }, /* 90 */ - { 0x01, 0, 1, "internet" }, /* 91 */ - { 0x04, 106, 1, "private" }, /* 92 */ - { 0x01, 0, 1, "enterprise" }, /* 93 */ - { 0x82, 99, 1, "" }, /* 94 */ - { 0x37, 0, 1, "Microsoft" }, /* 95 */ - { 0x0A, 0, 1, "" }, /* 96 */ - { 0x03, 0, 1, "" }, /* 97 */ - { 0x03, 0, 0, "msSGC" }, /* 98 */ - { 0x89, 0, 1, "" }, /* 99 */ - { 0x31, 0, 1, "" }, /* 100 */ - { 0x01, 0, 1, "" }, /* 101 */ - { 0x01, 0, 1, "" }, /* 102 */ - { 0x02, 0, 1, "" }, /* 103 */ - { 0x02, 105, 0, "" }, /* 104 */ - { 0x4B, 0, 0, "TCGID" }, /* 105 */ - { 0x05, 0, 1, "security" }, /* 106 */ - { 0x05, 0, 1, "mechanisms" }, /* 107 */ - { 0x07, 0, 1, "id-pkix" }, /* 108 */ - { 0x01, 111, 1, "id-pe" }, /* 109 */ - { 0x01, 0, 0, "authorityInfoAccess" }, /* 110 */ - { 0x03, 121, 1, "id-kp" }, /* 111 */ - { 0x01, 113, 0, "serverAuth" }, /* 112 */ - { 0x02, 114, 0, "clientAuth" }, /* 113 */ - { 0x03, 115, 0, "codeSigning" }, /* 114 */ - { 0x04, 116, 0, "emailProtection" }, /* 115 */ - { 0x05, 117, 0, "ipsecEndSystem" }, /* 116 */ - { 0x06, 118, 0, "ipsecTunnel" }, /* 117 */ - { 0x07, 119, 0, "ipsecUser" }, /* 118 */ - { 0x08, 120, 0, "timeStamping" }, /* 119 */ - { 0x09, 0, 0, "ocspSigning" }, /* 120 */ - { 0x08, 123, 1, "id-otherNames" }, /* 121 */ - { 0x05, 0, 0, "xmppAddr" }, /* 122 */ - { 0x0A, 128, 1, "id-aca" }, /* 123 */ - { 0x01, 125, 0, "authenticationInfo" }, /* 124 */ - { 0x02, 126, 0, "accessIdentity" }, /* 125 */ - { 0x03, 127, 0, "chargingIdentity" }, /* 126 */ - { 0x04, 0, 0, "group" }, /* 127 */ - { 0x30, 0, 1, "id-ad" }, /* 128 */ - { 0x01, 0, 1, "ocsp" }, /* 129 */ - { 0x01, 131, 0, "basic" }, /* 130 */ - { 0x02, 132, 0, "nonce" }, /* 131 */ - { 0x03, 133, 0, "crl" }, /* 132 */ - { 0x04, 134, 0, "response" }, /* 133 */ - { 0x05, 135, 0, "noCheck" }, /* 134 */ - { 0x06, 136, 0, "archiveCutoff" }, /* 135 */ - { 0x07, 0, 0, "serviceLocator" }, /* 136 */ - { 0x0E, 143, 1, "oiw" }, /* 137 */ - { 0x03, 0, 1, "secsig" }, /* 138 */ - { 0x02, 0, 1, "algorithms" }, /* 139 */ - { 0x07, 141, 0, "des-cbc" }, /* 140 */ - { 0x1A, 142, 0, "sha-1" }, /* 141 */ - { 0x1D, 0, 0, "sha-1WithRSASignature" }, /* 142 */ - { 0x24, 0, 1, "TeleTrusT" }, /* 143 */ - { 0x03, 0, 1, "algorithm" }, /* 144 */ - { 0x03, 0, 1, "signatureAlgorithm" }, /* 145 */ - { 0x01, 0, 1, "rsaSignature" }, /* 146 */ - { 0x02, 148, 0, "rsaSigWithripemd160" }, /* 147 */ - { 0x03, 149, 0, "rsaSigWithripemd128" }, /* 148 */ - { 0x04, 0, 0, "rsaSigWithripemd256" }, /* 149 */ - {0x60, 0, 1, "" }, /* 150 */ - { 0x86, 0, 1, "" }, /* 151 */ - { 0x48, 0, 1, "" }, /* 152 */ - { 0x01, 0, 1, "organization" }, /* 153 */ - { 0x65, 161, 1, "gov" }, /* 154 */ - { 0x03, 0, 1, "csor" }, /* 155 */ - { 0x04, 0, 1, "nistalgorithm" }, /* 156 */ - { 0x02, 0, 1, "hashalgs" }, /* 157 */ - { 0x01, 159, 0, "id-SHA-256" }, /* 158 */ - { 0x02, 160, 0, "id-SHA-384" }, /* 159 */ - { 0x03, 0, 0, "id-SHA-512" }, /* 160 */ - { 0x86, 0, 1, "" }, /* 161 */ - { 0xf8, 0, 1, "" }, /* 162 */ - { 0x42, 175, 1, "netscape" }, /* 163 */ - { 0x01, 170, 1, "" }, /* 164 */ - { 0x01, 166, 0, "nsCertType" }, /* 165 */ - { 0x03, 167, 0, "nsRevocationUrl" }, /* 166 */ - { 0x04, 168, 0, "nsCaRevocationUrl" }, /* 167 */ - { 0x08, 169, 0, "nsCaPolicyUrl" }, /* 168 */ - { 0x0d, 0, 0, "nsComment" }, /* 169 */ - { 0x03, 173, 1, "directory" }, /* 170 */ - { 0x01, 0, 1, "" }, /* 171 */ - { 0x03, 0, 0, "employeeNumber" }, /* 172 */ - { 0x04, 0, 1, "policy" }, /* 173 */ - { 0x01, 0, 0, "nsSGC" }, /* 174 */ - { 0x45, 0, 1, "verisign" }, /* 175 */ - { 0x01, 0, 1, "pki" }, /* 176 */ - { 0x09, 0, 1, "attributes" }, /* 177 */ - { 0x02, 179, 0, "messageType" }, /* 178 */ - { 0x03, 180, 0, "pkiStatus" }, /* 179 */ - { 0x04, 181, 0, "failInfo" }, /* 180 */ - { 0x05, 182, 0, "senderNonce" }, /* 181 */ - { 0x06, 183, 0, "recipientNonce" }, /* 182 */ - { 0x07, 184, 0, "transID" }, /* 183 */ - { 0x08, 0, 0, "extensionReq" } /* 184 */ + { 0xF6, 61, 1, "" }, /* 56 */ + { 0x7D, 0, 1, "NortelNetworks" }, /* 57 */ + { 0x07, 0, 1, "Entrust" }, /* 58 */ + { 0x41, 0, 1, "nsn-ce" }, /* 59 */ + { 0x00, 0, 0, "entrustVersInfo" }, /* 60 */ + { 0xF7, 0, 1, "" }, /* 61 */ + { 0x0D, 0, 1, "RSADSI" }, /* 62 */ + { 0x01, 89, 1, "PKCS" }, /* 63 */ + { 0x01, 72, 1, "PKCS-1" }, /* 64 */ + { 0x01, 66, 0, "rsaEncryption" }, /* 65 */ + { 0x02, 67, 0, "md2WithRSAEncryption" }, /* 66 */ + { 0x04, 68, 0, "md5WithRSAEncryption" }, /* 67 */ + { 0x05, 69, 0, "sha-1WithRSAEncryption" }, /* 68 */ + { 0x0B, 70, 0, "sha256WithRSAEncryption"}, /* 69 */ + { 0x0C, 71, 0, "sha384WithRSAEncryption"}, /* 70 */ + { 0x0D, 0, 0, "sha512WithRSAEncryption"}, /* 71 */ + { 0x07, 79, 1, "PKCS-7" }, /* 72 */ + { 0x01, 74, 0, "data" }, /* 73 */ + { 0x02, 75, 0, "signedData" }, /* 74 */ + { 0x03, 76, 0, "envelopedData" }, /* 75 */ + { 0x04, 77, 0, "signedAndEnvelopedData" }, /* 76 */ + { 0x05, 78, 0, "digestedData" }, /* 77 */ + { 0x06, 0, 0, "encryptedData" }, /* 78 */ + { 0x09, 0, 1, "PKCS-9" }, /* 79 */ + { 0x01, 81, 0, "E" }, /* 80 */ + { 0x02, 82, 0, "unstructuredName" }, /* 81 */ + { 0x03, 83, 0, "contentType" }, /* 82 */ + { 0x04, 84, 0, "messageDigest" }, /* 83 */ + { 0x05, 85, 0, "signingTime" }, /* 84 */ + { 0x06, 86, 0, "counterSignature" }, /* 85 */ + { 0x07, 87, 0, "challengePassword" }, /* 86 */ + { 0x08, 88, 0, "unstructuredAddress" }, /* 87 */ + { 0x0E, 0, 0, "extensionRequest" }, /* 88 */ + { 0x02, 92, 1, "digestAlgorithm" }, /* 89 */ + { 0x02, 91, 0, "md2" }, /* 90 */ + { 0x05, 0, 0, "md5" }, /* 91 */ + { 0x03, 0, 1, "encryptionAlgorithm" }, /* 92 */ + { 0x07, 0, 0, "3des-ede-cbc" }, /* 93 */ + {0x2B, 155, 1, "" }, /* 94 */ + { 0x06, 142, 1, "dod" }, /* 95 */ + { 0x01, 0, 1, "internet" }, /* 96 */ + { 0x04, 111, 1, "private" }, /* 97 */ + { 0x01, 0, 1, "enterprise" }, /* 98 */ + { 0x82, 104, 1, "" }, /* 99 */ + { 0x37, 0, 1, "Microsoft" }, /* 100 */ + { 0x0A, 0, 1, "" }, /* 101 */ + { 0x03, 0, 1, "" }, /* 102 */ + { 0x03, 0, 0, "msSGC" }, /* 103 */ + { 0x89, 0, 1, "" }, /* 104 */ + { 0x31, 0, 1, "" }, /* 105 */ + { 0x01, 0, 1, "" }, /* 106 */ + { 0x01, 0, 1, "" }, /* 107 */ + { 0x02, 0, 1, "" }, /* 108 */ + { 0x02, 110, 0, "" }, /* 109 */ + { 0x4B, 0, 0, "TCGID" }, /* 110 */ + { 0x05, 0, 1, "security" }, /* 111 */ + { 0x05, 0, 1, "mechanisms" }, /* 112 */ + { 0x07, 0, 1, "id-pkix" }, /* 113 */ + { 0x01, 116, 1, "id-pe" }, /* 114 */ + { 0x01, 0, 0, "authorityInfoAccess" }, /* 115 */ + { 0x03, 126, 1, "id-kp" }, /* 116 */ + { 0x01, 118, 0, "serverAuth" }, /* 117 */ + { 0x02, 119, 0, "clientAuth" }, /* 118 */ + { 0x03, 120, 0, "codeSigning" }, /* 119 */ + { 0x04, 121, 0, "emailProtection" }, /* 120 */ + { 0x05, 122, 0, "ipsecEndSystem" }, /* 121 */ + { 0x06, 123, 0, "ipsecTunnel" }, /* 122 */ + { 0x07, 124, 0, "ipsecUser" }, /* 123 */ + { 0x08, 125, 0, "timeStamping" }, /* 124 */ + { 0x09, 0, 0, "ocspSigning" }, /* 125 */ + { 0x08, 128, 1, "id-otherNames" }, /* 126 */ + { 0x05, 0, 0, "xmppAddr" }, /* 127 */ + { 0x0A, 133, 1, "id-aca" }, /* 128 */ + { 0x01, 130, 0, "authenticationInfo" }, /* 129 */ + { 0x02, 131, 0, "accessIdentity" }, /* 130 */ + { 0x03, 132, 0, "chargingIdentity" }, /* 131 */ + { 0x04, 0, 0, "group" }, /* 132 */ + { 0x30, 0, 1, "id-ad" }, /* 133 */ + { 0x01, 0, 1, "ocsp" }, /* 134 */ + { 0x01, 136, 0, "basic" }, /* 135 */ + { 0x02, 137, 0, "nonce" }, /* 136 */ + { 0x03, 138, 0, "crl" }, /* 137 */ + { 0x04, 139, 0, "response" }, /* 138 */ + { 0x05, 140, 0, "noCheck" }, /* 139 */ + { 0x06, 141, 0, "archiveCutoff" }, /* 140 */ + { 0x07, 0, 0, "serviceLocator" }, /* 141 */ + { 0x0E, 148, 1, "oiw" }, /* 142 */ + { 0x03, 0, 1, "secsig" }, /* 143 */ + { 0x02, 0, 1, "algorithms" }, /* 144 */ + { 0x07, 146, 0, "des-cbc" }, /* 145 */ + { 0x1A, 147, 0, "sha-1" }, /* 146 */ + { 0x1D, 0, 0, "sha-1WithRSASignature" }, /* 147 */ + { 0x24, 0, 1, "TeleTrusT" }, /* 148 */ + { 0x03, 0, 1, "algorithm" }, /* 149 */ + { 0x03, 0, 1, "signatureAlgorithm" }, /* 150 */ + { 0x01, 0, 1, "rsaSignature" }, /* 151 */ + { 0x02, 153, 0, "rsaSigWithripemd160" }, /* 152 */ + { 0x03, 154, 0, "rsaSigWithripemd128" }, /* 153 */ + { 0x04, 0, 0, "rsaSigWithripemd256" }, /* 154 */ + {0x60, 0, 1, "" }, /* 155 */ + { 0x86, 0, 1, "" }, /* 156 */ + { 0x48, 0, 1, "" }, /* 157 */ + { 0x01, 0, 1, "organization" }, /* 158 */ + { 0x65, 166, 1, "gov" }, /* 159 */ + { 0x03, 0, 1, "csor" }, /* 160 */ + { 0x04, 0, 1, "nistalgorithm" }, /* 161 */ + { 0x02, 0, 1, "hashalgs" }, /* 162 */ + { 0x01, 164, 0, "id-SHA-256" }, /* 163 */ + { 0x02, 165, 0, "id-SHA-384" }, /* 164 */ + { 0x03, 0, 0, "id-SHA-512" }, /* 165 */ + { 0x86, 0, 1, "" }, /* 166 */ + { 0xf8, 0, 1, "" }, /* 167 */ + { 0x42, 180, 1, "netscape" }, /* 168 */ + { 0x01, 175, 1, "" }, /* 169 */ + { 0x01, 171, 0, "nsCertType" }, /* 170 */ + { 0x03, 172, 0, "nsRevocationUrl" }, /* 171 */ + { 0x04, 173, 0, "nsCaRevocationUrl" }, /* 172 */ + { 0x08, 174, 0, "nsCaPolicyUrl" }, /* 173 */ + { 0x0d, 0, 0, "nsComment" }, /* 174 */ + { 0x03, 178, 1, "directory" }, /* 175 */ + { 0x01, 0, 1, "" }, /* 176 */ + { 0x03, 0, 0, "employeeNumber" }, /* 177 */ + { 0x04, 0, 1, "policy" }, /* 178 */ + { 0x01, 0, 0, "nsSGC" }, /* 179 */ + { 0x45, 0, 1, "verisign" }, /* 180 */ + { 0x01, 0, 1, "pki" }, /* 181 */ + { 0x09, 0, 1, "attributes" }, /* 182 */ + { 0x02, 184, 0, "messageType" }, /* 183 */ + { 0x03, 185, 0, "pkiStatus" }, /* 184 */ + { 0x04, 186, 0, "failInfo" }, /* 185 */ + { 0x05, 187, 0, "senderNonce" }, /* 186 */ + { 0x06, 188, 0, "recipientNonce" }, /* 187 */ + { 0x07, 189, 0, "transID" }, /* 188 */ + { 0x08, 0, 0, "extensionReq" } /* 189 */ }; diff --git a/src/libstrongswan/asn1/oid.h b/src/libstrongswan/asn1/oid.h index 49260c9f4..a29b1f0a1 100644 --- a/src/libstrongswan/asn1/oid.h +++ b/src/libstrongswan/asn1/oid.h @@ -29,56 +29,56 @@ extern const oid_t oid_names[]; #define OID_EXTENDED_KEY_USAGE 49 #define OID_TARGET_INFORMATION 50 #define OID_NO_REV_AVAIL 51 -#define OID_RSA_ENCRYPTION 60 -#define OID_MD2_WITH_RSA 61 -#define OID_MD5_WITH_RSA 62 -#define OID_SHA1_WITH_RSA 63 -#define OID_SHA256_WITH_RSA 64 -#define OID_SHA384_WITH_RSA 65 -#define OID_SHA512_WITH_RSA 66 -#define OID_PKCS7_DATA 68 -#define OID_PKCS7_SIGNED_DATA 69 -#define OID_PKCS7_ENVELOPED_DATA 70 -#define OID_PKCS7_SIGNED_ENVELOPED_DATA 71 -#define OID_PKCS7_DIGESTED_DATA 72 -#define OID_PKCS7_ENCRYPTED_DATA 73 -#define OID_PKCS9_EMAIL 75 -#define OID_PKCS9_CONTENT_TYPE 77 -#define OID_PKCS9_MESSAGE_DIGEST 78 -#define OID_PKCS9_SIGNING_TIME 79 -#define OID_MD2 85 -#define OID_MD5 86 -#define OID_3DES_EDE_CBC 88 -#define OID_AUTHORITY_INFO_ACCESS 110 -#define OID_OCSP_SIGNING 120 -#define OID_XMPP_ADDR 122 -#define OID_AUTHENTICATION_INFO 124 -#define OID_ACCESS_IDENTITY 125 -#define OID_CHARGING_IDENTITY 126 -#define OID_GROUP 127 -#define OID_OCSP 129 -#define OID_BASIC 130 -#define OID_NONCE 131 -#define OID_CRL 132 -#define OID_RESPONSE 133 -#define OID_NO_CHECK 134 -#define OID_ARCHIVE_CUTOFF 135 -#define OID_SERVICE_LOCATOR 136 -#define OID_DES_CBC 140 -#define OID_SHA1 141 -#define OID_SHA1_WITH_RSA_OIW 142 -#define OID_SHA256 158 -#define OID_SHA384 159 -#define OID_SHA512 160 -#define OID_NS_REVOCATION_URL 166 -#define OID_NS_CA_REVOCATION_URL 167 -#define OID_NS_CA_POLICY_URL 168 -#define OID_NS_COMMENT 169 -#define OID_PKI_MESSAGE_TYPE 178 -#define OID_PKI_STATUS 179 -#define OID_PKI_FAIL_INFO 180 -#define OID_PKI_SENDER_NONCE 181 -#define OID_PKI_RECIPIENT_NONCE 182 -#define OID_PKI_TRANS_ID 183 +#define OID_RSA_ENCRYPTION 65 +#define OID_MD2_WITH_RSA 66 +#define OID_MD5_WITH_RSA 67 +#define OID_SHA1_WITH_RSA 68 +#define OID_SHA256_WITH_RSA 69 +#define OID_SHA384_WITH_RSA 70 +#define OID_SHA512_WITH_RSA 71 +#define OID_PKCS7_DATA 73 +#define OID_PKCS7_SIGNED_DATA 74 +#define OID_PKCS7_ENVELOPED_DATA 75 +#define OID_PKCS7_SIGNED_ENVELOPED_DATA 76 +#define OID_PKCS7_DIGESTED_DATA 77 +#define OID_PKCS7_ENCRYPTED_DATA 78 +#define OID_PKCS9_EMAIL 80 +#define OID_PKCS9_CONTENT_TYPE 82 +#define OID_PKCS9_MESSAGE_DIGEST 83 +#define OID_PKCS9_SIGNING_TIME 84 +#define OID_MD2 90 +#define OID_MD5 91 +#define OID_3DES_EDE_CBC 93 +#define OID_AUTHORITY_INFO_ACCESS 115 +#define OID_OCSP_SIGNING 125 +#define OID_XMPP_ADDR 127 +#define OID_AUTHENTICATION_INFO 129 +#define OID_ACCESS_IDENTITY 130 +#define OID_CHARGING_IDENTITY 131 +#define OID_GROUP 132 +#define OID_OCSP 134 +#define OID_BASIC 135 +#define OID_NONCE 136 +#define OID_CRL 137 +#define OID_RESPONSE 138 +#define OID_NO_CHECK 139 +#define OID_ARCHIVE_CUTOFF 140 +#define OID_SERVICE_LOCATOR 141 +#define OID_DES_CBC 145 +#define OID_SHA1 146 +#define OID_SHA1_WITH_RSA_OIW 147 +#define OID_SHA256 163 +#define OID_SHA384 164 +#define OID_SHA512 165 +#define OID_NS_REVOCATION_URL 171 +#define OID_NS_CA_REVOCATION_URL 172 +#define OID_NS_CA_POLICY_URL 173 +#define OID_NS_COMMENT 174 +#define OID_PKI_MESSAGE_TYPE 183 +#define OID_PKI_STATUS 184 +#define OID_PKI_FAIL_INFO 185 +#define OID_PKI_SENDER_NONCE 186 +#define OID_PKI_RECIPIENT_NONCE 187 +#define OID_PKI_TRANS_ID 188 #endif /* OID_H_ */ diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt index 2b3c96ae3..bd5a26e43 100644 --- a/src/libstrongswan/asn1/oid.txt +++ b/src/libstrongswan/asn1/oid.txt @@ -54,6 +54,11 @@ 0x86 "" 0x48 "" 0x86 "" + 0xF6 "" + 0x7D "NortelNetworks" + 0x07 "Entrust" + 0x41 "nsn-ce" + 0x00 "entrustVersInfo" 0xF7 "" 0x0D "RSADSI" 0x01 "PKCS" diff --git a/src/libstrongswan/asn1/pem.c b/src/libstrongswan/asn1/pem.c index e88db249d..641805869 100755 --- a/src/libstrongswan/asn1/pem.c +++ b/src/libstrongswan/asn1/pem.c @@ -117,8 +117,10 @@ static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_s crypter->set_key(crypter, key); if (crypter->decrypt(crypter, *blob, *iv, &decrypted) != SUCCESS) { + crypter->destroy(crypter); return "data size is not multiple of block size"; } + crypter->destroy(crypter); memcpy(blob->ptr, decrypted.ptr, blob->len); chunk_free(&decrypted); diff --git a/src/libstrongswan/crypto/ca.c b/src/libstrongswan/crypto/ca.c index 07413e805..a78590954 100644 --- a/src/libstrongswan/crypto/ca.c +++ b/src/libstrongswan/crypto/ca.c @@ -345,7 +345,7 @@ static void add_crluri(private_ca_info_t *this, chunk_t uri) strncasecmp(uri.ptr, "file", 4) != 0 && strncasecmp(uri.ptr, "ftp", 3) != 0)) { - DBG1(" invalid crl uri '%#B'", uri); + DBG1(" invalid crl uri '%.*s'", uri.len, uri.ptr); return; } else @@ -399,7 +399,10 @@ void add_info (private_ca_info_t *this, const private_ca_info_t *that) while (iterator->iterate(iterator, (void**)&uri)) { - add_crluri(this, uri->get_encoding(uri)); + if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) + { + add_crluri(this, uri->get_encoding(uri)); + } } iterator->destroy(iterator); } @@ -411,7 +414,10 @@ void add_info (private_ca_info_t *this, const private_ca_info_t *that) while (iterator->iterate(iterator, (void**)&uri)) { - add_ocspuri(this, uri->get_encoding(uri)); + if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) + { + add_ocspuri(this, uri->get_encoding(uri)); + } } iterator->destroy(iterator); } diff --git a/src/libstrongswan/crypto/crypters/des_crypter.c b/src/libstrongswan/crypto/crypters/des_crypter.c index dc5a8ff55..655cc03ce 100644 --- a/src/libstrongswan/crypto/crypters/des_crypter.c +++ b/src/libstrongswan/crypto/crypters/des_crypter.c @@ -871,14 +871,15 @@ static int des_set_key(des_cblock *key, des_key_schedule *schedule) register unsigned char *in; register DES_LONG *k; register int i; + des_cblock odd; for (i = 0; i < sizeof(des_cblock); i++) { - (*key)[i] = odd_parity[(*key)[i]]; + odd[i] = odd_parity[(*key)[i]]; } k=(DES_LONG *)schedule; - in=(unsigned char *)key; + in=(unsigned char *)&odd; c2l(in,c); c2l(in,d); diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 673cbb828..ba0a76893 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -759,6 +759,24 @@ static bool equals_dn(private_identification_t *this, } /** + * Special implementation of identification_t.equals for RFC822 and FQDN. + */ +static bool equals_strcasecmp(private_identification_t *this, + private_identification_t *other) +{ + /* we do some extra sanity checks to check for invalid IDs with a + * terminating null in it. */ + if (this->encoded.len == other->encoded.len && + memchr(this->encoded.ptr, 0, this->encoded.len) == NULL && + memchr(other->encoded.ptr, 0, other->encoded.len) == NULL && + strncasecmp(this->encoded.ptr, other->encoded.ptr, this->encoded.len) == 0) + { + return TRUE; + } + return FALSE; +} + +/** * Default implementation of identification_t.matches. */ static bool matches_binary(private_identification_t *this, @@ -1094,6 +1112,8 @@ identification_t *identification_create_from_string(char *string) this->encoded.len = strlen(string + 1); this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_string; + this->public.equals = (bool (*) + (identification_t*,identification_t*))equals_strcasecmp; return &(this->public); } } @@ -1104,6 +1124,8 @@ identification_t *identification_create_from_string(char *string) this->encoded.len = strlen(string); this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_string; + this->public.equals = (bool (*) + (identification_t*,identification_t*))equals_strcasecmp; return &(this->public); } } @@ -1123,12 +1145,11 @@ identification_t *identification_create_from_encoding(id_type_t type, chunk_t en (identification_t*,identification_t*,int*))matches_any; break; case ID_FQDN: - this->public.matches = (bool (*) - (identification_t*,identification_t*,int*))matches_string; - break; case ID_RFC822_ADDR: this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_string; + this->public.equals = (bool (*) + (identification_t*,identification_t*))equals_strcasecmp; break; case ID_DER_ASN1_DN: this->public.equals = (bool (*) @@ -1152,3 +1173,4 @@ identification_t *identification_create_from_encoding(id_type_t type, chunk_t en } return &(this->public); } + diff --git a/src/libstrongswan/utils/iterator.h b/src/libstrongswan/utils/iterator.h index 02a15c534..b4ff85bfb 100644 --- a/src/libstrongswan/utils/iterator.h +++ b/src/libstrongswan/utils/iterator.h @@ -26,15 +26,46 @@ #include <library.h> +typedef enum hook_result_t hook_result_t; + +/** + * @brief Return value of an iterator hook. + * + * Returning HOOK_AGAIN is useful to "inject" additional elements in an + * iteration, HOOK_NEXT is the normal iterator behavior, and HOOK_SKIP may + * be used to filter elements out. + * + * @ingroup utils + */ +enum hook_result_t { + + /** + * A value was placed in out, hook is called again with the same "in" + */ + HOOK_AGAIN, + + /** + * A value was placed in out, hook is called again with next "in" (if any) + */ + HOOK_NEXT, + + /** + * No value in out, call again with next "in" (if any) + */ + HOOK_SKIP, +}; + /** * @brief Iterator hook function prototype. * * @param param user supplied parameter * @param in the value the hook receives from the iterator * @param out the value supplied as a result to the iterator - * @return TRUE to return "out", FALSE to skip this value + * @return a hook_result_t + * + * @ingroup utils */ -typedef bool (iterator_hook_t)(void *param, void *in, void **out); +typedef hook_result_t (iterator_hook_t)(void *param, void *in, void **out); typedef struct iterator_t iterator_t; @@ -45,8 +76,6 @@ typedef struct iterator_t iterator_t; * iterator_t defines an interface for iterating over collections. * It allows searching, deleting, updating and inserting. * - * Thanks to JMP for iterator lessons :-) - * * @b Constructors: * - via linked_list_t.create_iterator, or * - any other class which supports the iterator_t interface @@ -84,8 +113,11 @@ struct iterator_t { * Sometimes it is useful to hook in an iterator. The hook function is * called before any successful return of iterate(). It takes the * iterator value, may manipulate it (or the references object), and returns - * the value that the iterate() function returns. + * the value that the iterate() function returns. Depending on the hook + * return value, the hook is called again, called with next, or skipped. * A value of NULL deactivates the iterator hook. + * If an iterator is hooked, only the iterate() method is valid, + * all other methods behave undefined. * * @param this calling object * @param hook iterator hook which manipulates the iterated value diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index b8a023270..a28ebba51 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -410,7 +410,10 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) */ void __attribute__ ((constructor)) leak_detective_init() { - install_hooks(); + if (getenv("LEAK_DETECTIVE_DISABLE") == NULL) + { + install_hooks(); + } } /** @@ -418,8 +421,11 @@ void __attribute__ ((constructor)) leak_detective_init() */ void __attribute__ ((destructor)) leak_detective_cleanup() { - uninstall_hooks(); - report_leaks(); + if (getenv("LEAK_DETECTIVE_DISABLE") == NULL) + { + uninstall_hooks(); + report_leaks(); + } } /** @@ -431,6 +437,11 @@ void leak_detective_status(FILE *stream) size_t bytes = 0; memory_header_t *hdr = &first_header; + if (getenv("LEAK_DETECTIVE_DISABLE")) + { + return; + } + pthread_mutex_lock(&mutex); while ((hdr = hdr->next)) { diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c index de043a02e..de52ea46a 100644 --- a/src/libstrongswan/utils/linked_list.c +++ b/src/libstrongswan/utils/linked_list.c @@ -151,10 +151,10 @@ static int get_list_count(private_iterator_t *this) /** * default iterator hook which does nothing */ -static bool iterator_hook(void *param, void *in, void **out) +static hook_result_t iterator_hook(void *param, void *in, void **out) { *out = in; - return TRUE; + return HOOK_NEXT; } /** @@ -180,40 +180,43 @@ static void set_iterator_hook(private_iterator_t *this, iterator_hook_t *hook, */ static bool iterate(private_iterator_t *this, void** value) { - if (this->list->count == 0) - { - return FALSE; - } - if (this->current == NULL) + while (TRUE) { - this->current = (this->forward) ? this->list->first : this->list->last; - if (!this->hook(this->hook_param, this->current->value, value)) + if (this->forward) { - return iterate(this, value); + this->current = this->current ? this->current->next : this->list->first; } - return TRUE; - } - if (this->forward) - { - if (this->current->next == NULL) + else + { + this->current = this->current ? this->current->previous : this->list->last; + } + + if (this->current == NULL) { return FALSE; } - this->current = this->current->next; - if (!this->hook(this->hook_param, this->current->value, value)) + + switch (this->hook(this->hook_param, this->current->value, value)) { - return iterate(this, value); + case HOOK_AGAIN: + /* rewind */ + if (this->forward) + { + this->current = this->current->previous; + } + else + { + this->current = this->current->next; + } + break; + case HOOK_NEXT: + /* normal iteration */ + break; + case HOOK_SKIP: + /* advance */ + continue; } - return TRUE; - } - if (this->current->previous == NULL) - { - return FALSE; - } - this->current = this->current->previous; - if (!this->hook(this->hook_param, this->current->value, value)) - { - return iterate(this, value); + break; } return TRUE; } diff --git a/src/openac/Makefile.in b/src/openac/Makefile.in index 67396085c..fb295075a 100644 --- a/src/openac/Makefile.in +++ b/src/openac/Makefile.in @@ -142,6 +142,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/pluto/Makefile.in b/src/pluto/Makefile.in index e164717a9..4cefa58ca 100644 --- a/src/pluto/Makefile.in +++ b/src/pluto/Makefile.in @@ -179,6 +179,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ @@ -879,16 +880,16 @@ oid.h: oid.txt oid.pl $(PERL) oid.pl install-exec-local : - mkdir -p -m 755 $(confdir)/ipsec.d - mkdir -p -m 755 $(confdir)/ipsec.d/cacerts - mkdir -p -m 755 $(confdir)/ipsec.d/ocspcerts - mkdir -p -m 755 $(confdir)/ipsec.d/certs - mkdir -p -m 755 $(confdir)/ipsec.d/acerts - mkdir -p -m 755 $(confdir)/ipsec.d/aacerts - mkdir -p -m 755 $(confdir)/ipsec.d/crls - mkdir -p -m 755 $(confdir)/ipsec.d/reqs - mkdir -p -m 700 $(confdir)/ipsec.d/private - chown -R $(ipsecuid):$(ipsecgid) $(confdir)/ipsec.d + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/cacerts + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/ocspcerts + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/certs + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/acerts + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/aacerts + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/crls + mkdir -p -m 755 $(DESTDIR)$(confdir)/ipsec.d/reqs + mkdir -p -m 700 $(DESTDIR)$(confdir)/ipsec.d/private + chown -R $(ipsecuid):$(ipsecgid) $(DESTDIR)$(confdir)/ipsec.d # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/pluto/connections.c b/src/pluto/connections.c index 0d02b979c..c4d5dae4d 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -122,7 +122,7 @@ find_host_pair(const ip_address *myaddr, u_int16_t myport for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next) { if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport - && sameaddr(&p->him.addr, hisaddr) && p->him.port == hisport) + && sameaddr(&p->him.addr, hisaddr) && p->him.port == hisport) { if (prev != NULL) { @@ -162,15 +162,21 @@ connect_to_host_pair(struct connection *c) { if (oriented(*c)) { - struct host_pair *hp = find_host_pair(&c->spd.this.host_addr, c->spd.this.host_port - , &c->spd.that.host_addr, c->spd.that.host_port); + struct host_pair *hp; + + ip_address his_addr = (c->spd.that.allow_any) + ? *aftoinfo(addrtypeof(&c->spd.that.host_addr))->any + : c->spd.that.host_addr; + + hp = find_host_pair(&c->spd.this.host_addr, c->spd.this.host_port + , &his_addr, c->spd.that.host_port); if (hp == NULL) { /* no suitable host_pair -- build one */ hp = alloc_thing(struct host_pair, "host_pair"); hp->me.addr = c->spd.this.host_addr; - hp->him.addr = c->spd.that.host_addr; + hp->him.addr = his_addr; hp->me.port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port; hp->him.port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port; hp->initial_connection_sent = FALSE; @@ -632,24 +638,15 @@ format_end(char *buf strcpy(&host_id[len < 0? (ptrdiff_t)sizeof(host_id)-2 : 1 + len], "]"); } - /* [---hop] */ - hop[0] = '\0'; - hop_sep = ""; - if (that != NULL && !sameaddr(&this->host_nexthop, &that->host_addr)) - { - addrtot(&this->host_nexthop, 0, hop, sizeof(hop)); - hop_sep = "---"; - } - if (is_left) - snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s" - , open_brackets, client, close_brackets - , client_sep, host, host_port, host_id - , protoport, hop_sep, hop); + snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s" + , open_brackets, client, close_brackets, client_sep + , this->allow_any? "%":"" + , host, host_port, host_id, protoport); else - snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s" - , hop, hop_sep, host, host_port, host_id - , protoport, client_sep + snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s" + , this->allow_any? "%":"" + , host, host_port, host_id, protoport, client_sep , open_brackets, client, close_brackets); return strlen(buf); } @@ -855,6 +852,7 @@ extract_end(struct end *dst, const whack_end_t *src, const char *which) dst->has_client_wildcard = src->has_client_wildcard; dst->modecfg = src->modecfg; dst->hostaccess = src->hostaccess; + dst->allow_any = src->allow_any; dst->sendcert = src->sendcert; dst->updown = src->updown; dst->host_port = src->host_port; @@ -1067,7 +1065,8 @@ add_connection(const whack_message_t *wm) * or any wildcard ID to that end */ if (isanyaddr(&c->spd.this.host_addr) || c->spd.this.has_client_wildcard - || c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards) + || c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards + || c->spd.this.allow_any) { struct end t = c->spd.this; @@ -1095,7 +1094,7 @@ add_connection(const whack_message_t *wm) } else if ((isanyaddr(&c->spd.that.host_addr) && !NEVER_NEGOTIATE(c->policy)) || c->spd.that.has_client_wildcard || c->spd.that.has_port_wildcard - || c->spd.that.has_id_wildcards) + || c->spd.that.has_id_wildcards || c->spd.that.allow_any) { /* Opportunistic or Road Warrior or wildcard client subnet * or wildcard ID */ @@ -1263,6 +1262,8 @@ instantiate(struct connection *c, const ip_address *him c->instance_serial++; d = clone_thing(*c, "temporary connection"); + d->spd.that.allow_any = FALSE; + if (his_id != NULL) { passert(match_id(his_id, &d->spd.that.id, &wildcards)); @@ -1306,6 +1307,10 @@ instantiate(struct connection *c, const ip_address *him connect_to_host_pair(d); return d; + if (sameaddr(&d->spd.that.host_addr, &d->spd.this.host_nexthop)) + { + d->spd.this.host_nexthop = *him; + } } struct connection * @@ -1803,7 +1808,7 @@ initiate_connection(const char *name, int whackfd) loglog(RC_INITSHUNT , "cannot initiate an authby=never connection"); } - else if (c->kind != CK_PERMANENT) + else if (c->kind != CK_PERMANENT && !c->spd.that.allow_any) { if (isanyaddr(&c->spd.that.host_addr)) loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address"); @@ -1812,22 +1817,30 @@ initiate_connection(const char *name, int whackfd) } else { - /* We will only request an IPsec SA if policy isn't empty - * (ignoring Main Mode items). - * This is a fudge, but not yet important. - * If we are to proceed asynchronously, whackfd will be NULL_FD. - */ - c->policy |= POLICY_UP; /* do we have to prompt for a PIN code? */ if (c->spd.this.sc != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD) + { scx_get_pin(c->spd.this.sc, whackfd); - + } if (c->spd.this.sc != NULL && !c->spd.this.sc->valid) { loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN"); } else { + + if (c->spd.that.allow_any) + { + c = instantiate(c, &c->spd.that.host_addr, c->spd.that.host_port + , &c->spd.that.id); + } + + /* We will only request an IPsec SA if policy isn't empty + * (ignoring Main Mode items). + * This is a fudge, but not yet important. + * If we are to proceed asynchronously, whackfd will be NULL_FD. + */ + c->policy |= POLICY_UP; ipsecdoi_initiate(whackfd, c, c->policy, 1, SOS_NOBODY); whackfd = NULL_FD; /* protect from close */ } @@ -2975,51 +2988,6 @@ terminate_connection(const char *nm) } while (c != NULL); } -/* check nexthop safety - * Our nexthop must not be within a routed client subnet, and vice versa. - * Note: we don't think this is true. We think that KLIPS will - * not process a packet output by an eroute. - */ -#ifdef NEVER -//bool -//check_nexthop(const struct connection *c) -//{ -// struct connection *d; -// -// if (addrinsubnet(&c->spd.this.host_nexthop, &c->spd.that.client)) -// { -// loglog(RC_LOG_SERIOUS, "cannot perform routing for connection \"%s\"" -// " because nexthop is within peer's client network", -// c->name); -// return FALSE; -// } -// -// for (d = connections; d != NULL; d = d->next) -// { -// if (d->routing != RT_UNROUTED) -// { -// if (addrinsubnet(&c->spd.this.host_nexthop, &d->spd.that.client)) -// { -// loglog(RC_LOG_SERIOUS, "cannot do routing for connection \"%s\" -// " because nexthop is contained in" -// " existing routing for connection \"%s\"", -// c->name, d->name); -// return FALSE; -// } -// if (addrinsubnet(&d->spd.this.host_nexthop, &c->spd.that.client)) -// { -// loglog(RC_LOG_SERIOUS, "cannot do routing for connection \"%s\" -// " because it contains nexthop of" -// " existing routing for connection \"%s\"", -// c->name, d->name); -// return FALSE; -// } -// } -// } -// return TRUE; -//} -#endif /* NEVER */ - /* an ISAKMP SA has been established. * Note the serial number, and release any connections with * the same peer ID but different peer IP address. diff --git a/src/pluto/connections.h b/src/pluto/connections.h index df3af9dd4..40cbfc497 100644 --- a/src/pluto/connections.h +++ b/src/pluto/connections.h @@ -155,6 +155,7 @@ struct end { /* that end: give local addresses to clients */ bool hostaccess; /* allow access to host via iptables INPUT/OUTPUT */ /* rules if client behind host is a subnet */ + bool allow_any; /* IP address is subject to change */ certpolicy_t sendcert; /* whether or not to send the certificate */ }; diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c index d9b2167c8..a5bf82768 100644 --- a/src/pluto/plutomain.c +++ b/src/pluto/plutomain.c @@ -104,7 +104,8 @@ usage(const char *mess) " \\\n\t" "[--adns <pathname>]" "[--pkcs11module <path>]" - "[--pkcs11keepstate" + "[--pkcs11keepstate]" + "[--pkcs11initargs <string>]" #ifdef DEBUG " \\\n\t" "[--debug-none]" @@ -217,6 +218,11 @@ bool pkcs11_keep_state = FALSE; /* by default pluto does not allow pkcs11 proxy access via whack */ bool pkcs11_proxy = FALSE; +/* argument string to pass to PKCS#11 module. + * Not used for compliant modules, just for NSS softoken + */ +static const char *pkcs11_init_args = NULL; + int main(int argc, char **argv) { @@ -263,6 +269,7 @@ main(int argc, char **argv) #endif /* !USE_LWRES */ { "pkcs11module", required_argument, NULL, 'm' }, { "pkcs11keepstate", no_argument, NULL, 'k' }, + { "pkcs11initargs", required_argument, NULL, 'z' }, { "pkcs11proxy", no_argument, NULL, 'y' }, { "nat_traversal", no_argument, NULL, '1' }, { "keep_alive", required_argument, NULL, '2' }, @@ -432,6 +439,10 @@ main(int argc, char **argv) pkcs11_proxy = TRUE; continue; + case 'z': /* --pkcs11initargs */ + pkcs11_init_args = optarg; + continue; + #ifdef DEBUG case 'N': /* --debug-none */ base_debugging = DBG_NONE; @@ -593,7 +604,7 @@ main(int argc, char **argv) init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf); init_virtual_ip(virtual_private); - scx_init(pkcs11_module_path); /* load and initialize PKCS #11 module */ + scx_init(pkcs11_module_path, pkcs11_init_args); /* load and initialize PKCS #11 module */ xauth_init(); /* load and initialize XAUTH module */ init_rnd_pool(); init_secret(); diff --git a/src/pluto/smartcard.c b/src/pluto/smartcard.c index 744f8a6f3..067d0f046 100644 --- a/src/pluto/smartcard.c +++ b/src/pluto/smartcard.c @@ -690,12 +690,16 @@ scx_find_all_cert_objects(void) #endif /* - * load and initialize PKCS#11 cryptoki module + * load and initialize PKCS#11 cryptoki module + * + * init_args should be unused when we have a PKCS#11 compliant module, + * but NSS softoken breaks that API. */ void -scx_init(const char* module) +scx_init(const char* module, const char *init_args) { #ifdef SMARTCARD + CK_C_INITIALIZE_ARGS args = { .pReserved = init_args, }; CK_RV rv; if (scx_initialized) @@ -726,8 +730,8 @@ scx_init(const char* module) DBG(DBG_CONTROL | DBG_CRYPT, DBG_log("pkcs11 module initializing...") - ) - rv = pkcs11_functions->C_Initialize(NULL); + ) + rv = pkcs11_functions->C_Initialize(init_args ? &args : NULL); if (rv != CKR_OK) { plog("failed to initialize pkcs11 module: %s" diff --git a/src/pluto/smartcard.h b/src/pluto/smartcard.h index c004ca7dd..864f630a1 100644 --- a/src/pluto/smartcard.h +++ b/src/pluto/smartcard.h @@ -69,7 +69,7 @@ extern bool pkcs11_keep_state; extern bool pkcs11_proxy; extern smartcard_t* scx_parse_number_slot_id(const char *number_slot_id); -extern void scx_init(const char *module); +extern void scx_init(const char *module, const char *init_args); extern void scx_finalize(void); extern bool scx_establish_context(smartcard_t *sc); extern bool scx_login(smartcard_t *sc); diff --git a/src/pluto/vendor.c b/src/pluto/vendor.c index c2ea2b5a0..086cb4dd7 100644 --- a/src/pluto/vendor.c +++ b/src/pluto/vendor.c @@ -205,7 +205,8 @@ static struct vid_struct _vid_tab[] = { /* * strongSwan */ - DEC_MD5_VID(STRONGSWAN, "strongSwan 4.1.3") + DEC_MD5_VID(STRONGSWAN, "strongSwan 4.1.4") + DEC_MD5_VID(STRONGSWAN_4_1_3, "strongSwan 4.1.3") DEC_MD5_VID(STRONGSWAN_4_1_2, "strongSwan 4.1.2") DEC_MD5_VID(STRONGSWAN_4_1_1, "strongSwan 4.1.1") DEC_MD5_VID(STRONGSWAN_4_1_0, "strongSwan 4.1.0") @@ -218,6 +219,8 @@ static struct vid_struct _vid_tab[] = { DEC_MD5_VID(STRONGSWAN_4_0_1, "strongSwan 4.0.1") DEC_MD5_VID(STRONGSWAN_4_0_0, "strongSwan 4.0.0") + DEC_MD5_VID(STRONGSWAN_2_8_6, "strongSwan 2.8.6") + DEC_MD5_VID(STRONGSWAN_2_8_5, "strongSwan 2.8.5") DEC_MD5_VID(STRONGSWAN_2_8_4, "strongSwan 2.8.4") DEC_MD5_VID(STRONGSWAN_2_8_3, "strongSwan 2.8.3") DEC_MD5_VID(STRONGSWAN_2_8_2, "strongSwan 2.8.2") diff --git a/src/pluto/vendor.h b/src/pluto/vendor.h index 5ba65ea37..6c7eeafb3 100644 --- a/src/pluto/vendor.h +++ b/src/pluto/vendor.h @@ -89,18 +89,21 @@ enum known_vendorid { VID_STRONGSWAN_2_8_2 = 67, VID_STRONGSWAN_2_8_3 = 68, VID_STRONGSWAN_2_8_4 = 69, + VID_STRONGSWAN_2_8_5 = 70, + VID_STRONGSWAN_2_8_6 = 71, - VID_STRONGSWAN_4_0_0 = 70, - VID_STRONGSWAN_4_0_1 = 71, - VID_STRONGSWAN_4_0_2 = 72, - VID_STRONGSWAN_4_0_3 = 73, - VID_STRONGSWAN_4_0_4 = 74, - VID_STRONGSWAN_4_0_5 = 75, - VID_STRONGSWAN_4_0_6 = 76, - VID_STRONGSWAN_4_0_7 = 77, - VID_STRONGSWAN_4_1_0 = 78, - VID_STRONGSWAN_4_1_1 = 79, - VID_STRONGSWAN_4_1_2 = 80, + VID_STRONGSWAN_4_0_0 = 80, + VID_STRONGSWAN_4_0_1 = 81, + VID_STRONGSWAN_4_0_2 = 82, + VID_STRONGSWAN_4_0_3 = 83, + VID_STRONGSWAN_4_0_4 = 84, + VID_STRONGSWAN_4_0_5 = 85, + VID_STRONGSWAN_4_0_6 = 86, + VID_STRONGSWAN_4_0_7 = 87, + VID_STRONGSWAN_4_1_0 = 88, + VID_STRONGSWAN_4_1_1 = 89, + VID_STRONGSWAN_4_1_2 = 90, + VID_STRONGSWAN_4_1_3 = 91, /* 101 - 200 : NAT-Traversal */ VID_NATT_STENBERG_01 =101, diff --git a/src/scepclient/Makefile.in b/src/scepclient/Makefile.in index 798f09de8..665bda786 100644 --- a/src/scepclient/Makefile.in +++ b/src/scepclient/Makefile.in @@ -143,6 +143,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/starter/Makefile.am b/src/starter/Makefile.am index 7d5a4b69a..e2be69c01 100644 --- a/src/starter/Makefile.am +++ b/src/starter/Makefile.am @@ -9,7 +9,7 @@ INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto -I$(top_src AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" -DDEBUG starter_LDADD = loglite.o defs.o $(top_srcdir)/src/libfreeswan/libfreeswan.a EXTRA_DIST = parser.l parser.y keywords.txt ipsec.conf -dist_man_MANS = ipsec.conf.5 +dist_man_MANS = ipsec.conf.5 starter.8 MAINTAINERCLEANFILES = lex.yy.c y.tab.c y.tab.h keywords.c PLUTODIR=$(top_srcdir)/src/pluto diff --git a/src/starter/Makefile.in b/src/starter/Makefile.in index 432b3d6d5..a8ccfc626 100644 --- a/src/starter/Makefile.in +++ b/src/starter/Makefile.in @@ -46,7 +46,8 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = -am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" +am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" \ + "$(DESTDIR)$(man8dir)" ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(ipsec_PROGRAMS) am_starter_OBJECTS = y.tab.$(OBJEXT) netkey.$(OBJEXT) \ @@ -72,6 +73,7 @@ LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ SOURCES = $(starter_SOURCES) DIST_SOURCES = $(starter_SOURCES) man5dir = $(mandir)/man5 +man8dir = $(mandir)/man8 NROFF = nroff MANS = $(dist_man_MANS) ETAGS = etags @@ -136,6 +138,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ @@ -230,7 +233,7 @@ INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto -I$(top_src AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" -DDEBUG starter_LDADD = loglite.o defs.o $(top_srcdir)/src/libfreeswan/libfreeswan.a EXTRA_DIST = parser.l parser.y keywords.txt ipsec.conf -dist_man_MANS = ipsec.conf.5 +dist_man_MANS = ipsec.conf.5 starter.8 MAINTAINERCLEANFILES = lex.yy.c y.tab.c y.tab.h keywords.c PLUTODIR = $(top_srcdir)/src/pluto OPENACDIR = $(top_srcdir)/src/openac @@ -395,6 +398,51 @@ uninstall-man5: echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ done +install-man8: $(man8_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)" + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 8*) ;; \ + *) ext='8' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \ + done +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 8*) ;; \ + *) ext='8' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man8dir)/$$inst"; \ + done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ @@ -475,7 +523,7 @@ check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: - for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)"; do \ + for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am @@ -530,7 +578,7 @@ install-exec-am: install-exec-local install-info: install-info-am -install-man: install-man5 +install-man: install-man5 install-man8 installcheck-am: @@ -554,7 +602,7 @@ ps-am: uninstall-am: uninstall-info-am uninstall-ipsecPROGRAMS uninstall-man -uninstall-man: uninstall-man5 +uninstall-man: uninstall-man5 uninstall-man8 .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-ipsecPROGRAMS clean-libtool ctags distclean \ @@ -563,12 +611,12 @@ uninstall-man: uninstall-man5 install install-am install-data install-data-am install-exec \ install-exec-am install-exec-local install-info \ install-info-am install-ipsecPROGRAMS install-man install-man5 \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags uninstall uninstall-am \ - uninstall-info-am uninstall-ipsecPROGRAMS uninstall-man \ - uninstall-man5 + install-man8 install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am uninstall-ipsecPROGRAMS \ + uninstall-man uninstall-man5 uninstall-man8 lex.yy.c: y.tab.c parser.l parser.y parser.h diff --git a/src/starter/args.c b/src/starter/args.c index fb8424841..605794281 100644 --- a/src/starter/args.c +++ b/src/starter/args.c @@ -173,6 +173,7 @@ static const token_info_t token_info[] = { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL }, { ARG_STR, offsetof(starter_config_t, setup.eapdir), NULL }, { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL }, + { ARG_STR, offsetof(starter_config_t, setup.pkcs11initargs), NULL }, { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool }, { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool }, @@ -195,7 +196,7 @@ static const token_info_t token_info[] = { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL }, { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL }, { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL }, - { ARG_ULNG, offsetof(starter_conn_t, sa_keying_tries), NULL }, + { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ }, { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL }, { ARG_MISC, 0, NULL /* KW_REKEY */ }, { ARG_MISC, 0, NULL /* KW_REAUTH */ }, @@ -229,6 +230,7 @@ static const token_info_t token_info[] = { ARG_MISC, 0, NULL /* KW_NATIP */ }, { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool }, { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool }, + { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool }, { ARG_STR, offsetof(starter_end_t, updown), NULL }, { ARG_STR, offsetof(starter_end_t, id), NULL }, { ARG_STR, offsetof(starter_end_t, rsakey), NULL }, diff --git a/src/starter/confread.c b/src/starter/confread.c index e7a4789a9..2fe5b8ca7 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -181,14 +181,42 @@ kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token conn->addr_family = AF_INET6; anyaddr(conn->addr_family, &end->addr); } + else if (streq(value, "%group")) + { + ip_address any; + + conn->policy |= POLICY_GROUP | POLICY_TUNNEL; + anyaddr(conn->addr_family, &end->addr); + anyaddr(conn->tunnel_addr_family, &any); + initsubnet(&any, 0, '0', &end->subnet); + end->has_client = TRUE; + } else { + bool fallback_to_any = FALSE; + + if (value[0] == '%') + { + fallback_to_any = TRUE; + end->allow_any = TRUE; + value++; + } conn->addr_family = ip_version(value); ugh = ttoaddr(value, 0, conn->addr_family, &end->addr); if (ugh != NULL) { plog("# bad addr: %s=%s [%s]", name, value, ugh); - goto err; + if (fallback_to_any) + { + plog("# fallback to %s=%%any due to '%%' prefix"); + anyaddr(conn->addr_family, &end->addr); + end->allow_any = FALSE; + cfg->non_fatal_err++; + } + else + { + goto err; + } } } break; @@ -465,11 +493,12 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) case KW_EAP: /* TODO: a gperf function for all EAP types */ if (streq(kw->value, "aka")) + { conn->eap = 23; + } else if (streq(kw->value, "sim")) { conn->eap = 18; - } else { @@ -481,6 +510,23 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) } } break; + case KW_KEYINGTRIES: + if (streq(kw->value, "%forever")) + { + conn->sa_keying_tries = 0; + } + else + { + char *endptr; + + conn->sa_keying_tries = strtoul(kw->value, &endptr, 10); + if (*endptr != '\0') + { + plog("# bad integer value: %s=%s", kw->entry->name, kw->value); + cfg->err++; + } + } + break; case KW_REKEY: KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY) break; @@ -695,7 +741,79 @@ find_also_ca(const char* name, starter_ca_t *ca, starter_config_t *cfg) return NULL; } +/* + * free the memory used by also_t objects + */ +static void +free_also(also_t *head) +{ + while (head != NULL) + { + also_t *also = head; + + head = also->next; + pfree(also->name); + pfree(also); + } +} + +/* + * free the memory used by a starter_conn_t object + */ +static void +confread_free_conn(starter_conn_t *conn) +{ + free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left); + free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right); + free_args(KW_CONN_NAME, KW_CONN_LAST, (char *)conn); + free_also(conn->also); +} + +/* + * free the memory used by a starter_ca_t object + */ +static void +confread_free_ca(starter_ca_t *ca) +{ + free_args(KW_CA_NAME, KW_CA_LAST, (char *)ca); + free_also(ca->also); +} + +/* + * free the memory used by a starter_config_t object + */ +void +confread_free(starter_config_t *cfg) +{ + starter_conn_t *conn = cfg->conn_first; + starter_ca_t *ca = cfg->ca_first; + + free_args(KW_SETUP_FIRST, KW_SETUP_LAST, (char *)cfg); + + confread_free_conn(&cfg->conn_default); + + while (conn != NULL) + { + starter_conn_t *conn_aux = conn; + + conn = conn->next; + confread_free_conn(conn_aux); + pfree(conn_aux); + } + + confread_free_ca(&cfg->ca_default); + + while (ca != NULL) + { + starter_ca_t *ca_aux = ca; + + ca = ca->next; + confread_free_ca(ca_aux); + pfree(ca_aux); + } + pfree(cfg); +} /* * load and parse an IPsec configuration file @@ -709,6 +827,7 @@ confread_load(const char *file) starter_conn_t *conn; starter_ca_t *ca; + u_int total_err; u_int visit = 0; /* load IPSec configuration file */ @@ -748,6 +867,8 @@ confread_load(const char *file) /* load other ca sections */ for (sca = cfgp->ca_first; sca; sca = sca->next) { + u_int previous_err; + /* skip %default ca section */ if (streq(sca->name, "%default")) continue; @@ -761,13 +882,24 @@ confread_load(const char *file) ca->kw = sca->kw; ca->next = NULL; - if (cfg->ca_last) - cfg->ca_last->next = ca; - cfg->ca_last = ca; - if (!cfg->ca_first) - cfg->ca_first = ca; - + previous_err = cfg->err; load_ca(ca, ca->kw, cfg); + if (cfg->err > previous_err) + { + /* errors occurred - free the ca */ + confread_free_ca(ca); + cfg->non_fatal_err += cfg->err - previous_err; + cfg->err = previous_err; + } + else + { + /* success - insert the ca into the chained list */ + if (cfg->ca_last) + cfg->ca_last->next = ca; + cfg->ca_last = ca; + if (!cfg->ca_first) + cfg->ca_first = ca; + } } for (ca = cfg->ca_first; ca; ca = ca->next) @@ -806,6 +938,8 @@ confread_load(const char *file) /* load other conn sections */ for (sconn = cfgp->conn_first; sconn; sconn = sconn->next) { + u_int previous_err; + /* skip %default conn section */ if (streq(sconn->name, "%default")) continue; @@ -818,14 +952,25 @@ confread_load(const char *file) conn_default(sconn->name, conn, &cfg->conn_default); conn->kw = sconn->kw; conn->next = NULL; - - if (cfg->conn_last) - cfg->conn_last->next = conn; - cfg->conn_last = conn; - if (!cfg->conn_first) - cfg->conn_first = conn; - + + previous_err = cfg->err; load_conn(conn, conn->kw, cfg); + if (cfg->err > previous_err) + { + /* error occurred - free the conn */ + confread_free_conn(conn); + cfg->non_fatal_err += cfg->err - previous_err; + cfg->err = previous_err; + } + else + { + /* success - insert the conn into the chained list */ + if (cfg->conn_last) + cfg->conn_last->next = conn; + cfg->conn_last = conn; + if (!cfg->conn_first) + cfg->conn_first = conn; + } } /* in the second round do not parse also statements */ @@ -851,86 +996,12 @@ confread_load(const char *file) parser_free_conf(cfgp); - if (cfg->err) + total_err = cfg->err + cfg->non_fatal_err; + if (total_err > 0) { - plog("### %d parsing error%s ###", cfg->err, (cfg->err > 1)?"s":""); - confread_free(cfg); - cfg = NULL; + plog("### %d parsing error%s (%d fatal) ###" + , total_err, (total_err > 1)?"s":"", cfg->err); } return cfg; } - -/* - * free the memory used by also_t objects - */ -static void -free_also(also_t *head) -{ - while (head != NULL) - { - also_t *also = head; - - head = also->next; - pfree(also->name); - pfree(also); - } -} - -/* - * free the memory used by a starter_conn_t object - */ -static void -confread_free_conn(starter_conn_t *conn) -{ - free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left); - free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right); - free_args(KW_CONN_NAME, KW_CONN_LAST, (char *)conn); - free_also(conn->also); -} - -/* - * free the memory used by a starter_ca_t object - */ -static void -confread_free_ca(starter_ca_t *ca) -{ - free_args(KW_CA_NAME, KW_CA_LAST, (char *)ca); - free_also(ca->also); -} - -/* - * free the memory used by a starter_config_t object - */ -void -confread_free(starter_config_t *cfg) -{ - starter_conn_t *conn = cfg->conn_first; - starter_ca_t *ca = cfg->ca_first; - - free_args(KW_SETUP_FIRST, KW_SETUP_LAST, (char *)cfg); - - confread_free_conn(&cfg->conn_default); - - while (conn != NULL) - { - starter_conn_t *conn_aux = conn; - - conn = conn->next; - confread_free_conn(conn_aux); - pfree(conn_aux); - } - - confread_free_ca(&cfg->ca_default); - - while (ca != NULL) - { - starter_ca_t *ca_aux = ca; - - ca = ca->next; - confread_free_ca(ca_aux); - pfree(ca_aux); - } - - pfree(cfg); -} diff --git a/src/starter/confread.h b/src/starter/confread.h index 2fe75fcc6..970166c90 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -75,6 +75,7 @@ struct starter_end { certpolicy_t sendcert; bool firewall; bool hostaccess; + bool allow_any; char *updown; u_int16_t port; u_int8_t protocol; @@ -177,6 +178,7 @@ struct starter_config { char *virtual_private; char *eapdir; char *pkcs11module; + char *pkcs11initargs; bool pkcs11keepstate; bool pkcs11proxy; @@ -191,7 +193,8 @@ struct starter_config { defaultroute_t defaultroute; /* number of encountered parsing errors */ - u_int err; + u_int err; + u_int non_fatal_err; /* do we parse also statements */ bool parse_also; diff --git a/src/starter/interfaces.c b/src/starter/interfaces.c index a7c8efd44..a4baaa83d 100644 --- a/src/starter/interfaces.c +++ b/src/starter/interfaces.c @@ -33,449 +33,6 @@ #include "exec.h" #include "files.h" -#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) ) - -#define N_IPSEC_IF 4 - -struct st_ipsec_if { - char name[IFNAMSIZ]; - char phys[IFNAMSIZ]; - int up; -}; - -static struct st_ipsec_if _ipsec_if[N_IPSEC_IF]; - -static char * -_find_physical_iface(int sock, char *iface) -{ - static char _if[IFNAMSIZ]; - char *b; - struct ifreq req; - FILE *fd; - char line[BUF_LEN]; - - strncpy(req.ifr_name, iface, IFNAMSIZ); - if (ioctl(sock, SIOCGIFFLAGS, &req)==0) - { - if (req.ifr_flags & IFF_UP) - { - strncpy(_if, iface, IFNAMSIZ); - return _if; - } - } - else - { - /* If there is a file named /var/run/dynip/<iface>, look if we - * can get interface name from there (IP_PHYS) - */ - b = (char *)alloc_bytes(strlen(DYNIP_DIR) + strlen(iface) + 10, "iface"); - if (b) - { - sprintf(b, "%s/%s", DYNIP_DIR, iface); - fd = fopen(b, "r"); - pfree(b); - if (fd) - { - memset(_if, 0, sizeof(_if)); - memset(line, 0, sizeof(line)); - while (fgets(line, sizeof(line), fd) != 0) - { - if ((strncmp(line,"IP_PHYS=\"", 9) == 0) - && (line[strlen(line) - 2] == '"') - && (line[strlen(line) - 1] == '\n')) - { - strncpy(_if, line + 9, MIN(strlen(line) - 11, IFNAMSIZ)); - break; - } - else if ((strncmp(line,"IP_PHYS=", 8) == 0) - && (line[8] != '"') - && (line[strlen(line) - 1] == '\n')) - { - strncpy(_if, line + 8, MIN(strlen(line) - 9, IFNAMSIZ)); - break; - } - } - fclose(fd); - - if (*_if) - { - strncpy(req.ifr_name, _if, IFNAMSIZ); - if (ioctl(sock, SIOCGIFFLAGS, &req) == 0) - { - if (req.ifr_flags & IFF_UP) - return _if; - } - } - } - } - } - return NULL; -} - -int -starter_iface_find(char *iface, int af, ip_address *dst, ip_address *nh) -{ - char *phys; - struct ifreq req; - struct sockaddr_in *sa = (struct sockaddr_in *)(&req.ifr_addr); - int sock; - - if (!iface) - return -1; - - sock = socket(af, SOCK_DGRAM, 0); - if (sock < 0) - return -1; - - phys = _find_physical_iface(sock, iface); - if (!phys) - goto failed; - - strncpy(req.ifr_name, phys, IFNAMSIZ); - if (ioctl(sock, SIOCGIFFLAGS, &req)!=0) - goto failed; - if (!(req.ifr_flags & IFF_UP)) - goto failed; - - if ((req.ifr_flags & IFF_POINTOPOINT) - && nh - && ioctl(sock, SIOCGIFDSTADDR, &req) == 0) - { - if (sa->sin_family == af) - initaddr((const void *)&sa->sin_addr, sizeof(struct in_addr), af, nh); - } - if ((dst) && (ioctl(sock, SIOCGIFADDR, &req) == 0)) - { - if (sa->sin_family == af) - initaddr((const void *)&sa->sin_addr, sizeof(struct in_addr), af, dst); - } - close(sock); - return 0; - -failed: - close(sock); - return -1; -} - -static int -valid_str(char *str, unsigned int *pn, char **pphys -, defaultroute_t *defaultroute) -{ - if (streq(str, "%defaultroute")) - { - if (!defaultroute->defined) - { - return 0; - } - *pn = 0; - *pphys = defaultroute->iface; - } - else - { - if (strlen(str) < 8 - || str[0] != 'i' || str[1] != 'p' || str[2] !='s' || str[3] != 'e' - || str[4] != 'c' || str[5] < '0' || str[5] > '9' || str[6] != '=') - { - return 0; - } - *pn = str[5] - '0'; - *pphys = &(str[7]); - } - return 1; -} - -static int -_iface_up (int sock, struct st_ipsec_if *iface, char *phys -, unsigned int mtu, bool nat_t) -{ - struct ifreq req; - struct ipsectunnelconf *shc=(struct ipsectunnelconf *)&req.ifr_data; - short phys_flags; - int ret = 0; - /* sscholz@astaro.com: for network mask 32 bit - struct sockaddr_in *inp; - */ - - strncpy(req.ifr_name, phys, IFNAMSIZ); - if (ioctl(sock, SIOCGIFFLAGS, &req) !=0 ) - return ret; - phys_flags = req.ifr_flags; - - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - if (ioctl(sock, SIOCGIFFLAGS, &req) != 0) - return ret; - - if ((!(req.ifr_flags & IFF_UP)) || (!iface->up)) - { - DBG(DBG_CONTROL, - DBG_log("attaching interface %s to %s", iface->name, phys) - ) - ret = 1; - } - - if ((*iface->phys) && (strcmp(iface->phys, phys) != 0 )) - { - /* tncfg --detach if phys has changed */ - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - ioctl(sock, IPSEC_DEL_DEV, &req); - ret = 1; - } - - /* tncfg --attach */ - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - strncpy(shc->cf_name, phys, sizeof(shc->cf_name)); - ioctl(sock, IPSEC_SET_DEV, &req); - - /* set ipsec addr = phys addr */ - strncpy(req.ifr_name, phys, IFNAMSIZ); - if (ioctl(sock, SIOCGIFADDR, &req) == 0) - { - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - ioctl(sock, SIOCSIFADDR, &req); - } - - /* set ipsec mask = phys mask */ - strncpy(req.ifr_name, phys, IFNAMSIZ); - if (ioctl(sock, SIOCGIFNETMASK, &req) == 0) - { - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - /* sscholz@astaro.com: changed netmask to 32 bit - * in order to prevent network routes from being created - - inp = (struct sockaddr_in *)&req.ifr_addr; - inp->sin_addr.s_addr = 0xFFFFFFFFL; - - */ - ioctl(sock, SIOCSIFNETMASK, &req); - } - - /* set other flags & addr */ - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - if (ioctl(sock, SIOCGIFFLAGS, &req)==0) - { -/* removed by sscholz@astaro.com (caused trouble with DSL/ppp0) */ -/* if (phys_flags & IFF_POINTOPOINT) - { - req.ifr_flags |= IFF_POINTOPOINT; - req.ifr_flags &= ~IFF_BROADCAST; - ioctl(sock, SIOCSIFFLAGS, &req); - strncpy(req.ifr_name, phys, IFNAMSIZ); - if (ioctl(sock, SIOCGIFDSTADDR, &req) == 0) - { - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - ioctl(sock, SIOCSIFDSTADDR, &req); - } - } - else - */ - if (phys_flags & IFF_BROADCAST) - { - req.ifr_flags &= ~IFF_POINTOPOINT; - req.ifr_flags |= IFF_BROADCAST; - ioctl(sock, SIOCSIFFLAGS, &req); - strncpy(req.ifr_name, phys, IFNAMSIZ); - if (ioctl(sock, SIOCGIFBRDADDR, &req) == 0) - { - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - ioctl(sock, SIOCSIFBRDADDR, &req); - } - } - else - { - req.ifr_flags &= ~IFF_POINTOPOINT; - req.ifr_flags &= ~IFF_BROADCAST; - ioctl(sock, SIOCSIFFLAGS, &req); - } - } - - /* - * guess MTU = phys interface MTU - ESP Overhead - * - * ESP overhead : 10+16+7+2+12=57 -> 60 by security - * NAT-T overhead : 20 - */ - if (mtu == 0) - { - strncpy(req.ifr_name, phys, IFNAMSIZ); - ioctl(sock, SIOCGIFMTU, &req); - mtu = req.ifr_mtu - 60; - if (nat_t) - mtu -= 20; - } - /* set MTU */ - if (mtu) - { - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - req.ifr_mtu = mtu; - ioctl(sock, SIOCSIFMTU, &req); - } - - /* ipsec interface UP */ - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - if (ioctl(sock, SIOCGIFFLAGS, &req) == 0) - { - req.ifr_flags |= IFF_UP; - ioctl(sock, SIOCSIFFLAGS, &req); - } - - iface->up = 1; - strncpy(iface->phys, phys, IFNAMSIZ); - return ret; -} - -static int -_iface_down(int sock, struct st_ipsec_if *iface) -{ - struct ifreq req; - int ret = 0; - - iface->up = 0; - - strncpy(req.ifr_name, iface->name, IFNAMSIZ); - if (ioctl(sock, SIOCGIFFLAGS, &req)!=0) - return ret; - - if (req.ifr_flags & IFF_UP) - { - DBG(DBG_CONTROL, - DBG_log("shutting down interface %s/%s", iface->name, iface->phys) - ) - req.ifr_flags &= ~IFF_UP; - ioctl(sock, SIOCSIFFLAGS, &req); - ret = 1; - } - - /* unset addr */ - memset(&req.ifr_addr, 0, sizeof(req.ifr_addr)); - req.ifr_addr.sa_family = AF_INET; - ioctl(sock, SIOCSIFADDR, &req); - - /* tncfg --detach */ - ioctl(sock, IPSEC_DEL_DEV, &req); - - memset(iface->phys, 0, sizeof(iface->phys)); - - return ret; -} - -void -starter_ifaces_init(void) -{ - int i; - - memset(_ipsec_if, 0, sizeof(_ipsec_if)); - for (i = 0; i < N_IPSEC_IF; i++) - snprintf(_ipsec_if[i].name, IFNAMSIZ, "ipsec%d", i); -} - -void -starter_ifaces_clear (void) -{ - int sock; - unsigned int i; - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - return; - - for (i = 0; i < N_IPSEC_IF; i++) - _iface_down (sock, &(_ipsec_if[i])); -} - -int -starter_ifaces_load(char **ifaces, unsigned int omtu, bool nat_t -, defaultroute_t *defaultroute) -{ - char *tmp_phys, *phys; - int n; - char **i; - int sock; - int j, found; - int ret = 0; - struct ifreq physreq, ipsecreq; // re-attach interface - struct sockaddr_in *inp1, *inp2; // re-attach interface - - DBG(DBG_CONTROL, - DBG_log("starter_ifaces_load()") - ) - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - return -1; - - for (j = 0; j < N_IPSEC_IF; j++) - { - found = 0; - - for (i = ifaces; i && *i; i++) - { - if (valid_str(*i, &n, &tmp_phys, defaultroute) - && tmp_phys - && n >= 0 - && n < N_IPSEC_IF) - { - if (n==j) - { - if (found) - { - plog( "ignoring duplicate entry for interface ipsec%d", j); - } - else - { - found++; - phys = _find_physical_iface(sock, tmp_phys); - - /* Re-attach ipsec interface if IP address changes - * sscholz@astaro.com - */ - if (phys) - { - memset ((void*)&physreq, 0, sizeof(physreq)); - memset ((void*)&ipsecreq, 0, sizeof(ipsecreq)); - strncpy(physreq.ifr_name, phys, IFNAMSIZ); - sprintf(ipsecreq.ifr_name, "ipsec%d", j); - ioctl(sock, SIOCGIFADDR, &physreq); - ioctl(sock, SIOCGIFADDR, &ipsecreq); - inp1 = (struct sockaddr_in *)&physreq.ifr_addr; - inp2 = (struct sockaddr_in *)&ipsecreq.ifr_addr; - if (inp1->sin_addr.s_addr != inp2->sin_addr.s_addr) - { - plog("IP address of physical interface changed " - "-> reinit of ipsec interface"); - _iface_down (sock, &(_ipsec_if[n])); - } - ret += _iface_up (sock, &(_ipsec_if[n]), phys, omtu, nat_t); - } - else - { - ret += _iface_down (sock, &(_ipsec_if[n])); - } - } - } - } - else if (j == 0) - { - /* Only log in the first loop */ - plog("ignoring invalid interface '%s'", *i); - } - } - if (!found) - ret += _iface_down (sock, &(_ipsec_if[j])); - } - - close(sock); - return ret; /* = number of changes - 'whack --listen' if > 0 */ -} - -/* - * initialize a defaultroute_t struct - */ -static void -init_defaultroute(defaultroute_t *defaultroute) -{ - memset(defaultroute, 0, sizeof(defaultroute_t)); -} - /* * discover the default route via /proc/net/route */ @@ -486,7 +43,7 @@ get_defaultroute(defaultroute_t *defaultroute) char line[BUF_LEN]; bool first = TRUE; - init_defaultroute(defaultroute); + memset(defaultroute, 0, sizeof(defaultroute_t)); fd = fopen("/proc/net/route", "r"); diff --git a/src/starter/interfaces.h b/src/starter/interfaces.h index 9898c0516..ed6b0ef57 100644 --- a/src/starter/interfaces.h +++ b/src/starter/interfaces.h @@ -28,12 +28,6 @@ typedef struct { ip_address nexthop; } defaultroute_t; -extern void starter_ifaces_init (void); -extern int starter_iface_find(char *iface, int af, ip_address *dst - , ip_address *nh); -extern int starter_ifaces_load (char **ifaces, unsigned int omtu, bool nat_t - , defaultroute_t *defaultroute); -extern void starter_ifaces_clear (void); extern void get_defaultroute(defaultroute_t *defaultroute); diff --git a/src/starter/invokepluto.c b/src/starter/invokepluto.c index 240d98391..5ea47f69f 100644 --- a/src/starter/invokepluto.c +++ b/src/starter/invokepluto.c @@ -187,6 +187,11 @@ starter_start_pluto (starter_config_t *cfg, bool debug) arg[argc++] = "--pkcs11module"; arg[argc++] = cfg->setup.pkcs11module; } + if (cfg->setup.pkcs11initargs) + { + arg[argc++] = "--pkcs11initargs"; + arg[argc++] = cfg->setup.pkcs11initargs; + } if (cfg->setup.pkcs11keepstate) { arg[argc++] = "--pkcs11keepstate"; diff --git a/src/starter/ipsec.conf b/src/starter/ipsec.conf index 76b85b23a..b1e5d5e0c 100644 --- a/src/starter/ipsec.conf +++ b/src/starter/ipsec.conf @@ -1,14 +1,8 @@ # ipsec.conf - strongSwan IPsec configuration file -# Manual: man 5 ipsec.conf -# Help: http://www.strongswan.org/docs/readme.htm - -version 2.0 # conforms to second version of ipsec.conf specification - # basic configuration config setup - # Debug-logging controls: "none" for (almost) none, "all" for lots. # plutodebug=all # crlcheckinterval=600 # strictcrlpolicy=yes diff --git a/src/starter/ipsec.conf.5 b/src/starter/ipsec.conf.5 index c80c5166b..2dbcfcfd7 100644 --- a/src/starter/ipsec.conf.5 +++ b/src/starter/ipsec.conf.5 @@ -1,4 +1,4 @@ -.TH IPSEC.CONF 5 "20 Jan 2006" +.TH IPSEC.CONF 5 "27 Jun 2007" .\" RCSID $Id: ipsec.conf.5,v 1.2 2006/01/22 15:33:46 as Exp $ .SH NAME ipsec.conf \- IPsec configuration and connections @@ -143,7 +143,7 @@ section specifies general configuration information for IPsec, a .B conn section specifies an IPsec connection, while a .B ca -section specifies special properties a certification authority. +section specifies special properties of a certification authority. .SH "CONN SECTIONS" A .B conn @@ -158,13 +158,12 @@ Here's a simple example: .ft B .ta 1c conn snt - left=10.11.11.1 - leftsubnet=10.0.1.0/24 - leftnexthop=172.16.55.66 - right=192.168.22.1 - rightsubnet=10.0.2.0/24 - rightnexthop=172.16.88.99 + left=192.168.0.1 + leftsubnet=10.1.0.0/16 + right=192.168.0.2 + rightsubnet=10.1.0.0/16 keyingtries=%forever + auto=add .ft .fi .PP @@ -172,7 +171,7 @@ A note on terminology: There are two kinds of communications going on: transmission of user IP packets, and gateway-to-gateway negotiations for keying, rekeying, and general control. The path to control the connection is called 'ISAKMP SA' in IKEv1 and -'IKE SA' in the IKEv2 protocol. That what is beeing negotiated, the kernel +'IKE SA' in the IKEv2 protocol. That what is being negotiated, the kernel level data path, is called 'IPsec SA'. strongSwan currently uses two separate keying daemons. Pluto handles all IKEv1 connections, Charon is the new daemon supporting the IKEv2 protocol. @@ -220,151 +219,47 @@ Unless otherwise noted, for a connection to work, in general it is necessary for the two ends to agree exactly on the values of these parameters. .TP 14 -.B type -the type of the connection; currently the accepted values -are -.B tunnel -(the default) -signifying a host-to-host, host-to-subnet, or subnet-to-subnet tunnel; -.BR transport , -signifying host-to-host transport mode; -.BR passthrough , -signifying that no IPsec processing should be done at all; -.BR drop , -signifying that packets should be discarded; and -.BR reject , -signifying that packets should be discarded and a diagnostic ICMP returned. -Charon currently supports only -.BR tunnel -and -.BR transport -connection types. -.TP -.B left -(required) -the IP address of the left participant's public-network interface, -in any form accepted by -.IR ipsec_ttoaddr (3) -or one of several magic values. -If it is -.BR %defaultroute , -and -the -.B config -.B setup -section's, -.B interfaces -specification contains -.BR %defaultroute, -.B left -will be filled in automatically with the local address -of the default-route interface (as determined at IPsec startup time); -this also overrides any value supplied for -.BR leftnexthop . -(Either -.B left -or -.B right -may be -.BR %defaultroute , -but not both.) -The value -.B %any -signifies an address to be filled in (by automatic keying) during -negotiation. -.TP -.B leftsubnet -private subnet behind the left participant, expressed as -\fInetwork\fB/\fInetmask\fR -(actually, any form acceptable to -.IR ipsec_ttosubnet (3)); -if omitted, essentially assumed to be \fIleft\fB/32\fR, -signifying that the left end of the connection goes to the left participant -only. When using IKEv2, the configured subnet of the peers may differ, the -protocol narrows it to the greates common subnet. -.TP -.B leftnexthop -next-hop gateway IP address for the left participant's connection -to the public network; -defaults to -.B %direct -(meaning -.IR right ). -If the value is to be overridden by the -.B left=%defaultroute -method (see above), -an explicit value must -.I not -be given. -If that method is not being used, -but -.B leftnexthop -is -.BR %defaultroute , -and -.B interfaces=%defaultroute -is used in the -.B config -.B setup -section, -the next-hop gateway address of the default-route interface -will be used. -The magic value -.B %direct -signifies a value to be filled in (by automatic keying) -with the peer's address. -Relevant only locally, other end need not agree on it. Currently not supported -in IKEv2. +.B ah +AH authentication algorithm to be used +for the connection, e.g. +.B hmac-md5. .TP -.B leftupdown -what ``updown'' script to run to adjust routing and/or firewalling -when the status of the connection -changes (default -.BR "ipsec _updown" ). -May include positional parameters separated by white space -(although this requires enclosing the whole string in quotes); -including shell metacharacters is unwise. -See -.IR ipsec_pluto (8) -for details. -Relevant only locally, other end need not agree on it. IKEv2 uses the updown -script to insert firewall rules only. Routing is not support and will be -implemented directly into Charon. +.B auth +whether authentication should be done as part of +ESP encryption, or separately using the AH protocol; +acceptable values are +.B esp +(the default) and +.BR ah . +The IKEv2 daemon currently supports only ESP. .TP -.B leftfirewall -whether the left participant is doing forwarding-firewalling -(including masquerading) for traffic from \fIleftsubnet\fR, -which should be turned off (for traffic to the other subnet) -once the connection is established; +.B authby +how the two security gateways should authenticate each other; acceptable values are -.B yes -and (the default) -.BR no . -May not be used in the same connection description with -.BR leftupdown . -Implemented as a parameter to the default -.I updown -script. -See notes below. -Relevant only locally, other end need not agree on it. - -If one or both security gateways are doing forwarding firewalling -(possibly including masquerading), -and this is specified using the firewall parameters, -tunnels established with IPsec are exempted from it -so that packets can flow unchanged through the tunnels. -(This means that all subnets connected in this manner must have -distinct, non-overlapping subnet address blocks.) -This is done by the default -.I updown -script (see -.IR ipsec_pluto (8)). - -In situations calling for more control, -it may be preferable for the user to supply his own -.I updown -script, -which makes the appropriate adjustments for his system. +.B secret +or +.B psk +for shared secrets, +.B rsasig +for RSA digital signatures (the default), +.B secret|rsasig +for either, and +.B never +if negotiation is never to be attempted or accepted (useful for shunt-only conns). +Digital signatures are superior in every way to shared secrets. In IKEv2, the +two ends must not agree on this parameter, it is relevant for the +outbound authentication method only. +IKEv1 additionally supports the values +.B xauthpsk +and +.B xauthrsasig +that will enable eXtended AUTHentication (XAUTH) in addition to IKEv1 main mode +based on shared secrets or digital RSA signatures, respectively. +IKEv2 additionally supports the value +.B eap, +which indicates an initiator to request EAP authentication. The EAP method to +use is selected by the server (see +.B eap). .TP .B auto what operation, if any, should be done automatically at IPsec startup; @@ -375,8 +270,7 @@ currently-accepted values are , .B start and -.B ignore -. +.BR ignore . .B add loads a connection without starting it. .B route @@ -396,34 +290,6 @@ both ends should use .B auto=start to ensure that any reboot causes immediate renegotiation). .TP -.B auth -whether authentication should be done as part of -ESP encryption, or separately using the AH protocol; -acceptable values are -.B esp -(the default) and -.BR ah . -The IKEv2 daemon currently supports only ESP. -.TP -.B authby -how the two security gateways should authenticate each other; -acceptable values are -.B secret -for shared secrets, -.B rsasig -for RSA digital signatures (the default), -.B secret|rsasig -for either, and -.B never -if negotiation is never to be attempted or accepted (useful for shunt-only conns). -Digital signatures are superior in every way to shared secrets. In IKEv2, the -two ends must not agree on this parameter, it is relevant for the own -authentication method only. IKEv2 additionally supports the value -.B eap, -which indicates an initiator to request EAP authentication. The EAP method to -use is selected by the server (see -.B eap). -.TP .B compress whether IPComp compression of content is proposed on the connection (link-level compression does not work on encrypted data, @@ -447,24 +313,26 @@ controls the use of the Dead Peer Detection protocol (DPD, RFC 3706) where R_U_THERE notification messages (IKEv1) or empty INFORMATIONAL messages (IKEv2) are periodically sent in order to check the liveliness of the IPsec peer. The values -.B clear -and -.B hold -both activate DPD. If no activity is detected, all connections with a dead peer +.BR clear , +.BR hold , +and +.B restart +all activate DPD. If no activity is detected, all connections with a dead peer are stopped and unrouted ( .B clear -) or put in the hold state ( +), put in the hold state ( .B hold -). For -.B IKEv1 -, the default is +) or restarted ( +.B restart +). +For IKEv1, the default is .B none which disables the active sending of R_U_THERE notifications. Nevertheless pluto will always send the DPD Vendor ID during connection set up in order to signal the readiness to act passively as a responder if the peer -wants to use DPD. For -.B IKEv2, none -does't make sense, as all messages are used to detect dead peers. If specified, +wants to use DPD. For IKEv2, +.B none +does't make sense, since all messages are used to detect dead peers. If specified, it has the same meaning as the default ( .B clear ). @@ -481,16 +349,28 @@ defines the timeout interval, after which all connections to a peer are deleted in case of inactivity. This only applies to IKEv1, in IKEv2 the default retransmission timeout applies, as every exchange is used to detect dead peers. .TP -.B failureshunt -what to do with packets when negotiation fails. -The default is -.BR none : -no shunt; -.BR passthrough , -.BR drop , -and -.B reject -have the obvious meanings. Has no effect in IKEv2 yet. +.B eap +defines the EAP type to be used if +.B authby=eap +is selected. Acceptable values are +.B aka +for EAP-AKA and +.B sim +for EAP-SIM. +.TP +.B esp +ESP encryption/authentication algorithm to be used +for the connection, e.g. +.B 3des-md5 +(encryption-integrity-[dh-group]). If dh-group is specified, CHILD_SA setup +and rekeying include a separate diffe hellman exchange (IKEv2 only). +.TP +.B ike +IKE/ISAKMP SA encryption/authentication algorithm to be used, e.g. +.B aes128-sha1-modp2048 +(encryption-integrity-dhgroup). In IKEv2, multiple algorithms and proposals +may be included, such as +.B aes128-aes256-sha1-modp1536-modp2048,3des-sha1-md5-modp1024. .TP .B ikelifetime how long the keying channel of a connection ('ISAKMP/IKE SA') @@ -545,6 +425,52 @@ although if they do not, there will be some clutter of superseded connections on the end which thinks the lifetime is longer. .TP +.B left +(required) +the IP address of the left participant's public-network interface, +in any form accepted by +.IR ttoaddr (3) +or one of several magic values. +If it is +.BR %defaultroute , +.B left +will be filled in automatically with the local address +of the default-route interface (as determined at IPsec startup time). +(Either +.B left +or +.B right +may be +.BR %defaultroute , +but not both.) +The value +.B %any +signifies an address to be filled in (by automatic keying) during +negotiation. The prefix +.B % +in front of a fully-qualified domain name or an IP address will implicitly set +.B leftallowany=yes. +If the domain name cannot be resolved into an IP address at IPsec startup or update time +then +.B left=%any +and +.B leftallowany=no +will be assumed. +.TP +.B leftallowany +a modifier for +.B left +, making it behave as +.B %any +although a concrete IP address has been assigned. +Recommended for dynamic IP addresses that can be resolved by DynDNS at IPsec startup or +update time. +Acceptable values are +.B yes +and +.B no +(the default). +.TP .B leftca the distinguished name of a certificate authority which is required to lie in the trust path going from the left participant's certificate up @@ -553,8 +479,7 @@ to the root certification authority. .B leftcert the path to the left participant's X.509 certificate. The file can be coded either in PEM or DER format. OpenPGP certificates are supported as well. -Both absolute paths or paths relative to -.B /etc/ipsec.d/certs +Both absolute paths or paths relative to \fI/etc/ipsec.d/certs\fP are accepted. By default .B leftcert sets @@ -566,14 +491,57 @@ The left participant's ID can be overriden by specifying a .B leftid value which must be certified by the certificate, though. .TP +.B leftfirewall +whether the left participant is doing forwarding-firewalling +(including masquerading) using iptables for traffic from \fIleftsubnet\fR, +which should be turned off (for traffic to the other subnet) +once the connection is established; +acceptable values are +.B yes +and +.B no +(the default). +May not be used in the same connection description with +.BR leftupdown . +Implemented as a parameter to the default \fBipsec _updown\fR script. +See notes below. +Relevant only locally, other end need not agree on it. + +If one or both security gateways are doing forwarding firewalling +(possibly including masquerading), +and this is specified using the firewall parameters, +tunnels established with IPsec are exempted from it +so that packets can flow unchanged through the tunnels. +(This means that all subnets connected in this manner must have +distinct, non-overlapping subnet address blocks.) +This is done by the default \fBipsec _updown\fR script (see +.IR pluto (8)). + +In situations calling for more control, +it may be preferable for the user to supply his own +.I updown +script, +which makes the appropriate adjustments for his system. +.TP .B leftgroups a comma separated list of group names. If the .B leftgroups parameter is present then the peer must be a member of at least one of the groups defined by the parameter. Group membership must be certified -by a valid attribute certificate stored in \fI/etc/ipsec.d/acerts\fP thas has been +by a valid attribute certificate stored in \fI/etc/ipsec.d/acerts/\fP thas has been issued to the peer by a trusted Authorization Authority stored in -\fI/etc/ipsec.d/aacerts\fP. Attribute certificates are not supported in IKEv2 yet. +\fI/etc/ipsec.d/aacerts/\fP. Attribute certificates are not supported in IKEv2 yet. +.TP +.B lefthostaccess +inserts a pair of INPUT and OUTPUT iptables rules using the default +\fBipsec _updown\fR script, thus allowing access to the host itself +in the case where the host's internal interface is part of the +negotiated client subnet. +Acceptable values are +.B yes +and +.B no +(the default). .TP .B leftid how @@ -582,24 +550,67 @@ should be identified for authentication; defaults to .BR left . Can be an IP address (in any -.IR ipsec_ttoaddr (3) +.IR ttoaddr (3) syntax) or a fully-qualified domain name preceded by .B @ (which is used as a literal string and not resolved). +.TP +.B leftnexthop +this parameter is not needed any more because the NETKEY IPsec stack does +not require explicit routing entries for the traffic to be tunneled. +.TP +.B leftprotoport +restrict the traffic selector to a single protocol and/or port. +Examples: +.B leftprotoport=tcp/http +or +.B leftprotoport=6/80 +or +.B leftprotoport=udp +.TP +.B leftrsasigkey +the left participant's +public key for RSA signature authentication, +in RFC 2537 format using +.IR ttodata (3) +encoding. The magic value -.B %myid -stands for the current setting of \fImyid\fP. -This is set in \fBconfig setup\fP or by \fIipsec_whack\fP(8)), or, if not set, -it is the IP address in \fB%defaultroute\fP (if that is supported by a TXT record in its reverse domain), or otherwise -it is the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined. +.B %none +means the same as not specifying a value (useful to override a default). +The value +.B %cert +(the default) +means that the key is extracted from a certificate. +The identity used for the left participant +must be a specific host, not +.B %any +or another magic value. +.B Caution: +if two connection descriptions +specify different public keys for the same +.BR leftid , +confusion and madness will ensue. +.TP +.B leftsendcert +Accepted values are +.B never +or +.BR no , +.B always +or +.BR yes , +and +.BR ifasked . .TP .B leftsourceip The internal source IP to use in a tunnel, also known as virtual IP. If the value is -.B %modeconfig +.BR %modeconfig , +.BR %modecfg , +.BR %config , or -.B %config, +.B %cfg, an address is requested from the peer. In IKEv2, a defined address is requested, but the server may change it. If the server does not support it, the address is enforced. @@ -611,9 +622,47 @@ value is on the responder side, the initiator must propose a address which is then echoed back. .TP +.B leftsubnet +private subnet behind the left participant, expressed as +\fInetwork\fB/\fInetmask\fR +(actually, any form acceptable to +.IR ttosubnet (3)); +if omitted, essentially assumed to be \fIleft\fB/32\fR, +signifying that the left end of the connection goes to the left participant +only. When using IKEv2, the configured subnet of the peers may differ, the +protocol narrows it to the greates common subnet. +.TP .B leftsubnetwithin +the peer can propose any subnet or single IP address that fits within the +range defined by +.BR leftsubnetwithin. Not relevant for IKEv2, as subnets are narrowed. .TP +.B leftupdown +what ``updown'' script to run to adjust routing and/or firewalling +when the status of the connection +changes (default +.BR "ipsec _updown" ). +May include positional parameters separated by white space +(although this requires enclosing the whole string in quotes); +including shell metacharacters is unwise. +See +.IR pluto (8) +for details. +Relevant only locally, other end need not agree on it. IKEv2 uses the updown +script to insert firewall rules only. Routing is not support and will be +implemented directly into Charon. +.TP +.B modeconfig +defines which mode is used to assign a virtual IP. +Accepted values are +.B push +and +.B pull +(the default). +Currently relevant for IKEv1 only since IKEv2 always uses the configuration +payload in pull mode. +.TP .B pfs whether Perfect Forward Secrecy of keys is desired on the connection's keying channel @@ -623,9 +672,20 @@ acceptable values are .B yes (the default) and -.BR no -. IKEv2 always uses PFS for IKE_SA rekeying. PFS for rekeying IPsec SAs is -currently not supported. +.BR no. +IKEv2 always uses PFS for IKE_SA rekeying whereas for CHILD_SA rekeying +PFS is enforced by defining a Diffie-Hellman modp group in the +.B esp +parameter. +.TP +.B reauth +whether rekeying of an IKE_SA should also reauthenticate the peer. In IKEv1, +reauthentication is always done. In IKEv2, a value of +.B no +rekeys without uninstalling the IPsec SAs, a value of +.B yes +(the default) creates a new IKE_SA from scratch and tries to recreate +all IPsec SAs. .TP .B rekey whether a connection should be renegotiated when it is about to expire; @@ -634,8 +694,7 @@ acceptable values are (the default) and .BR no . -The two ends need not agree, -but while a value of +The two ends need not agree, but while a value of .B no prevents Pluto/Charon from requesting renegotiation, it does not prevent responding to renegotiation requested from the other end, @@ -643,15 +702,6 @@ so .B no will be largely ineffective unless both ends agree on it. .TP -.B reauth -whether rekeying of an IKE_SA should also reauthenticate the peer. In IKEv1, -reauthentication is always done. In IKEv2, a value of -.B no -rekeys without uninstalling the IPsec SAs, a value of -.B yes -(the default) creates a new IKE_SA from scratch and tries to recreate -all IPsec SAs. -.TP .B rekeyfuzz maximum percentage by which .B rekeymargin @@ -661,7 +711,7 @@ acceptable values are an integer, which may exceed 100, followed by a `%' (default set by -.IR ipsec_pluto (8), +.IR pluto (8), currently .BR 100% ). The value of @@ -684,24 +734,36 @@ begin; acceptable values as for .BR 9m ). Relevant only locally, other end need not agree on it. .TP -.B ike -IKE/ISAKMP SA encryption/authentication algorithm to be used, e.g. -.B aes128-sha1-modp2048 -(encryption-integrity-dhgroup). In IKEv2, multiple algorithms and proposals -may be included, such as -.B aes128-aes256-sha1-modp1536-modp2048,3des-sha1-md5-modp1024. -.TP -.B esp -ESP encryption/authentication algorithm to be used -for the connection, e.g. -.B 3des-md5 -(encryption-integrity-[dh-group]). If dh-group is specified, CHILD_SA setup -and rekeying include a separate diffe hellman exchange (IKEv2 only). +.B type +the type of the connection; currently the accepted values +are +.B tunnel +(the default) +signifying a host-to-host, host-to-subnet, or subnet-to-subnet tunnel; +.BR transport , +signifying host-to-host transport mode; +.BR passthrough , +signifying that no IPsec processing should be done at all; +.BR drop , +signifying that packets should be discarded; and +.BR reject , +signifying that packets should be discarded and a diagnostic ICMP returned. +Charon currently supports only +.BR tunnel +and +.BR transport +connection types. .TP -.B ah -AH authentication algorithm to be used -for the connection, e.g. -.B hmac-md5. +.B xauth +specifies the role in the XAUTH protocol if activated by +.B authby=xauthpsk +or +.B authby=xauthrsasig. +Accepted values are +.B server +and +.B client +(the default). .SH "CA SECTIONS" This are optional sections that can be used to assign special parameters to a Certification Authority (CA). These parameters are not @@ -721,14 +783,25 @@ defines a path to the CA certificate either relative to .B crluri defines a CRL distribution point (ldap, http, or file URI) .TP +.B crluri1 +synonym for +.B crluri. +.TP .B crluri2 defines an alternative CRL distribution point (ldap, http, or file URI) .TP .B ldaphost -defines an ldap host. +defines an ldap host. Currently used by IKEv1 only. .TP .B ocspuri defines an OCSP URI. +.TP +.B ocspuri1 +synonym for +.B ocspuri. +.TP +.B ocspuri2 +defines an alternative OCSP URI. Currently used by IKEv2 only. .SH "CONFIG SECTIONS" At present, the only .B config @@ -736,7 +809,7 @@ section known to the IPsec software is the one named .BR setup , which contains information used when the software is being started (see -.IR ipsec_setup (8)). +.IR starter (8)). Here's an example: .PP .ne 8 @@ -744,10 +817,9 @@ Here's an example: .ft B .ta 1c config setup - interfaces="ipsec0=eth1 ipsec1=ppp0" - klipsdebug=none plutodebug=all - manualstart= + crlcheckinterval=10m + strictcrlpolicy=yes .ft .fi .PP @@ -759,78 +831,107 @@ names in a .B setup section are: .TP 14 -.B myid -the identity to be used for -.BR %myid . -.B %myid -is used in the implicit policy group conns and can be used as -an identity in explicit conns. -If unspecified, -.B %myid -is set to the IP address in \fB%defaultroute\fP (if that is supported by a TXT record in its reverse domain), or otherwise -the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined. -An explicit value generally starts with ``\fB@\fP''. -.TP -.B interfaces -virtual and physical interfaces for IPsec to use: -a single -\fIvirtual\fB=\fIphysical\fR pair, a (quoted!) list of pairs separated -by white space, or -.BR %none . -One of the pairs may be written as -.BR %defaultroute , -which means: find the interface \fId\fR that the default route points to, -and then act as if the value was ``\fBipsec0=\fId\fR''. -.B %defaultroute -is the default; -.B %none -must be used to denote no interfaces. -If -.B %defaultroute -is used (implicitly or explicitly) -information about the default route and its interface is noted for -use by -.IR ipsec_manual (8) +.B cachecrls +certificate revocation lists (CRLs) fetched via http or ldap will be cached in +\fI/etc/ipsec.d/crls/\fR under a unique file name derived from the certification +authority's public key. +Accepted values are +.B yes and -.IR ipsec_auto (8).) -.TP -.B forwardcontrol -whether -.I setup -should turn IP forwarding on -(if it's not already on) as IPsec is started, -and turn it off again (if it was off) as IPsec is stopped; -acceptable values are +.B no +(the default). +.TP +.B charonstart +whether to start the IKEv2 Charon daemon or not. +Accepted values are +.B yes +(the default) +or +.BR no . +.TP +.B crlcheckinterval +interval in seconds. CRL fetching is enabled if the value is greater than zero. +Asynchronous, periodic checking for fresh CRLs is currently done by the +IKEv1 Pluto daemon only. +.TP +.B dumpdir +in what directory should things started by \fBipsec starter\fR +(notably the Pluto and Charon daemons) be allowed to dump core? +The empty value (the default) means they are not +allowed to. +This feature is currently not yet supported by \fBipsec starter\fR. +.TP +.B plutostart +whether to start the IKEv1 Pluto daemon or not. +Accepted values are .B yes -and (the default) +(the default) +or .BR no . -For this to have full effect, forwarding must be -disabled before the hardware interfaces are brought -up (e.g., -.B "net.ipv4.ip_forward\ =\ 0" -in Red Hat 6.x -.IR /etc/sysctl.conf ), -because IPsec doesn't get control early enough to do that. -.TP -.B rp_filter -whether and how -.I setup -should adjust the reverse path filtering mechanism for the -physical devices to be used. -Values are \fB%unchanged\fP (to leave it alone) -or \fB0\fP, \fB1\fP, \fB2\fP (values to set it to). -\fI/proc/sys/net/ipv4/conf/PHYS/rp_filter\fP -is badly documented; it must be \fB0\fP in many cases -for ipsec to function. -The default value for the parameter is \fB0\fP. -.TP -.B syslog -the -.IR syslog (2) -``facility'' name and priority to use for -startup/shutdown log messages, -default -.BR daemon.error . +.TP +.B strictcrlpolicy +defines if a fresh CRL must be available in order for the peer authentication based +on RSA signatures to succeed. +Accepted values are +.B yes +and +.B no +(the default). +IKEv2 additionally recognizes +.B ifuri +which reverts to +.B yes +if at least one CRL URI is defined and to +.B no +if no URI is known. +.PP +The following +.B config section +parameters are used by the IKEv1 Pluto daemon only: +.TP +.B keep_alive +interval in seconds between NAT keep alive packets, the default being 20 seconds. +.TP +.B nat_traversal +activates NAT traversal by accepting source ISAKMP ports different from udp/500 and +being able of floating to udp/4500 if a NAT situation is detected. +Accepted values are +.B yes +and +.B no +(the default). +.B nocrsend +no certificate request payloads will be sent. +Accepted values are +.B yes +and +.B no +(the default). +Used by IKEv1 only, NAT traversal always being active in IKEv2. +.TP +.B pkcs11initargs +non-standard argument string for PKCS#11 C_Initialize() function; +required by NSS softoken. +.TP +.B pkcs11module +defines the path to a dynamically loadable PKCS #11 library. +.TP +.B pkcs11keepstate +PKCS #11 login sessions will be kept during the whole lifetime of the keying +daemon. Useful with pin-pad smart card readers. +Accepted values are +.B yes +and +.B no +(the default). +.TP +.B pkcs11proxy +Pluto will act as a PKCS #11 proxy accessible via the whack interface. +Accepted values are +.B yes +and +.B no +(the default). .TP .B plutodebug how much Pluto debugging output should be logged. @@ -847,57 +948,11 @@ Otherwise only the specified types of output prefix, separated by white space) are enabled; for details on available debugging types, see -.IR ipsec_pluto (8). -.TP -.B charondebug -how much Charon debugging output should be logged. -A comma separated list containing type level/pairs may -be specified, e.g: -.B dmn 3, ike 1, net -1. -Acceptable values for types are -.B dmn, mgr, ike, chd, job, cfg, knl, net, enc, lib -and the level is one of -.B -1, 0, 1, 2, 3, 4 -(for silent, audit, control, controlmore, raw, private) +.IR pluto (8). .TP -.B plutoopts -additional options to pass to pluto upon startup. See -.IR ipsec_pluto (8). -.TP -.B plutostderrlog -do not use syslog, but rather log to stderr, and direct stderr to the -argument file. -.TP -.B dumpdir -in what directory should things started by -.I setup -(notably the Pluto daemon) be allowed to -dump core? -The empty value (the default) means they are not -allowed to. -.TP -.B pluto -whether to start Pluto or not; -Values are -.B yes -(the default) -or -.B no -(useful only in special circumstances). -.TP -.B plutowait -should Pluto wait for each -negotiation attempt that is part of startup to -finish before proceeding with the next? -Values are -.B yes -or -.BR no -(the default). -.TP -.B prepluto -shell command to run before starting Pluto -(e.g., to decrypt an encrypted copy of the +.B postpluto +shell command to run after starting Pluto +(e.g., to remove a decrypted copy of the .I ipsec.secrets file). It's run in a very simple way; @@ -908,9 +963,9 @@ so running interactive commands is difficult unless they use or equivalent for their interaction. Default is none. .TP -.B postpluto -shell command to run after starting Pluto -(e.g., to remove a decrypted copy of the +.B prepluto +shell command to run before starting Pluto +(e.g., to decrypt an encrypted copy of the .I ipsec.secrets file). It's run in a very simple way; @@ -921,6 +976,43 @@ so running interactive commands is difficult unless they use or equivalent for their interaction. Default is none. .TP +.B virtual_private +defines private networks using a wildcard notation. +.TP +.B uniqueids +whether a particular participant ID should be kept unique, +with any new (automatically keyed) +connection using an ID from a different IP address +deemed to replace all old ones using that ID; +acceptable values are +.B yes +(the default) +and +.BR no . +Participant IDs normally \fIare\fR unique, +so a new (automatically-keyed) connection using the same ID is +almost invariably intended to replace an old one. +.PP +The following +.B config section +parameters are used by the IKEv2 Charon daemon only: +.TP +.B charondebug +how much Charon debugging output should be logged. +A comma separated list containing type level/pairs may +be specified, e.g: +.B dmn 3, ike 1, net -1. +Acceptable values for types are +.B dmn, mgr, ike, chd, job, cfg, knl, net, enc, lib +and the level is one of +.B -1, 0, 1, 2, 3, 4 +(for silent, audit, control, controlmore, raw, private). +.PP +The following +.B config section +parameters only make sense if the KLIPS IPsec stack +is used instead of the default NETKEY stack of the Linux 2.6 kernel: +.TP .B fragicmp whether a tunnel's need to fragment a packet should be reported back with an ICMP message, @@ -939,37 +1031,26 @@ acceptable values are .B yes (the default) and -.BR no . +.BR no .TP -.B uniqueids -whether a particular participant ID should be kept unique, -with any new (automatically keyed) -connection using an ID from a different IP address -deemed to replace all old ones using that ID; -acceptable values are -.B yes -(the default) -and -.BR no . -Participant IDs normally \fIare\fR unique, -so a new (automatically-keyed) connection using the same ID is -almost invariably intended to replace an old one. +.B interfaces +virtual and physical interfaces for IPsec to use: +a single +\fIvirtual\fB=\fIphysical\fR pair, a (quoted!) list of pairs separated +by white space, or +.BR %none . +One of the pairs may be written as +.BR %defaultroute , +which means: find the interface \fId\fR that the default route points to, +and then act as if the value was ``\fBipsec0=\fId\fR''. +.B %defaultroute +is the default; +.B %none +must be used to denote no interfaces. .TP .B overridemtu value that the MTU of the ipsec\fIn\fR interface(s) should be set to, overriding IPsec's (large) default. -This parameter is needed only in special situations. -.TP -.B nat_traversal -.TP -.B crlcheckinterval -.TP -.B strictcrlpolicy -.TP -.B pkcs11module -.TP -.B pkcs11keepstate - .SH CHOOSING A CONNECTION .PP When choosing a connection to apply to an outbound packet caught with a @@ -988,87 +1069,20 @@ information about the client subnets to complete the instantiation. .SH FILES .nf /etc/ipsec.conf +/etc/ipsec.d/aacerts +/etc/ipsec.d/acerts /etc/ipsec.d/cacerts /etc/ipsec.d/certs /etc/ipsec.d/crls -/etc/ipsec.d/aacerts -/etc/ipsec.d/acerts .SH SEE ALSO -ipsec(8), ipsec_ttoaddr(8), ipsec_auto(8), ipsec_manual(8), ipsec_rsasigkey(8) +ipsec(8), pluto(8), starter(8), ttoaddr(3), ttodata(3) .SH HISTORY -Written for the FreeS/WAN project -<http://www.freeswan.org> -by Henry Spencer. Extended for the strongSwan project +Written for the FreeS/WAN project by Henry Spencer. +Extended for the strongSwan project <http://www.strongswan.org> -by Andreas Steffen. Updated to respect IKEv2 specific configuration -by Martin Willi. +by Andreas Steffen. IKEv2-specific features by Martin Willi. .SH BUGS .PP -When -.B type -or -.B failureshunt -is set to -.B drop -or -.BR reject, -strongSwan blocks outbound packets using eroutes, but assumes inbound -blocking is handled by the firewall. strongSwan offers firewall hooks -via an ``updown'' script. However, the default -.B ipsec _updown -provides no help in controlling a modern firewall. -.PP -Including attributes of the keying channel -(authentication methods, -.BR ikelifetime , -etc.) -as an attribute of a connection, -rather than of a participant pair, is dubious and incurs limitations. -.PP -.IR Ipsec_manual -is not nearly as generous about the syntax of subnets, -addresses, etc. as the usual strongSwan user interfaces. -Four-component dotted-decimal must be used for all addresses. -It -.I is -smart enough to translate bit-count netmasks to dotted-decimal form. -.PP -It would be good to have a line-continuation syntax, -especially for the very long lines involved in -RSA signature keys. -.PP -The ability to specify different identities, -.BR authby , -and public keys for different automatic-keyed connections -between the same participants is misleading; -this doesn't work dependably because the identity of the participants -is not known early enough. -This is especially awkward for the ``Road Warrior'' case, -where the remote IP address is specified as -.BR 0.0.0.0 , -and that is considered to be the ``participant'' for such connections. -.PP -In principle it might be necessary to control MTU on an -interface-by-interface basis, -rather than with the single global override that -.B overridemtu -provides. -.PP -A number of features which \fIcould\fR be implemented in -both manual and automatic keying -actually are not yet implemented for manual keying. -This is unlikely to be fixed any time soon. -.PP -If conns are to be added before DNS is available, -\fBleft=\fP\fIFQDN\fP, -\fBleftnextop=\fP\fIFQDN\fP, -and -.B leftrsasigkey=%dnsonload +If conns are to be added before DNS is available, \fBleft=\fP\fIFQDN\fP will fail. -.IR ipsec_pluto (8) -does not actually use the public key for our side of a conn but it -isn't generally known at a add-time which side is ours (Road Warrior -and Opportunistic conns are currently exceptions). -.PP -The \fBmyid\fP option does not affect explicit \fB ipsec auto \-\-add\fP or \fBipsec auto \-\-replace\fP commands for implicit conns. diff --git a/src/starter/keywords.c b/src/starter/keywords.c index 215b95ad6..f7f24eefb 100644 --- a/src/starter/keywords.c +++ b/src/starter/keywords.c @@ -56,12 +56,12 @@ struct kw_entry { kw_token_t token; }; -#define TOTAL_KEYWORDS 90 +#define TOTAL_KEYWORDS 93 #define MIN_WORD_LENGTH 3 #define MAX_WORD_LENGTH 17 #define MIN_HASH_VALUE 15 -#define MAX_HASH_VALUE 188 -/* maximum key range = 174, duplicates = 0 */ +#define MAX_HASH_VALUE 209 +/* maximum key range = 195, duplicates = 0 */ #ifdef __GNUC__ __inline @@ -77,32 +77,32 @@ hash (str, len) { static const unsigned char asso_values[] = { - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 40, - 10, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 80, 189, 20, - 75, 5, 95, 0, 30, 0, 189, 55, 0, 45, - 0, 35, 20, 189, 15, 70, 40, 15, 20, 189, - 0, 25, 0, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, - 189, 189, 189, 189, 189, 189 + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 40, + 5, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 90, 210, 25, + 75, 5, 85, 0, 95, 0, 210, 55, 0, 25, + 0, 70, 20, 210, 15, 70, 40, 20, 5, 210, + 5, 65, 0, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210 }; return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]] + asso_values[(unsigned char)str[len - 1]]; } @@ -116,7 +116,8 @@ static const struct kw_entry wordlist[] = {"leftfirewall", KW_LEFTFIREWALL}, {""}, {""}, {""}, {"leftsubnetwithin", KW_LEFTSUBNETWITHIN}, - {""}, {""}, {""}, {""}, + {""}, {""}, {""}, + {"virtual_private", KW_VIRTUAL_PRIVATE}, {"rightupdown", KW_RIGHTUPDOWN}, {""}, {"rightfirewall", KW_RIGHTFIREWALL}, @@ -129,30 +130,23 @@ static const struct kw_entry wordlist[] = {""}, {"leftnexthop", KW_LEFTNEXTHOP}, {"leftsourceip", KW_LEFTSOURCEIP}, - {""}, {""}, - {"virtual_private", KW_VIRTUAL_PRIVATE}, - {"crluri", KW_CRLURI}, - {""}, - {"leftrsasigkey", KW_LEFTRSASIGKEY}, - {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {"rightnatip", KW_RIGHTNATIP}, - {""}, + {"crluri", KW_CRLURI}, {"rightnexthop", KW_RIGHTNEXTHOP}, {"rightsourceip", KW_RIGHTSOURCEIP}, {"left", KW_LEFT}, - {"rekey", KW_REKEY}, - {"crlcheckinterval", KW_CRLCHECKINTERVAL}, + {""}, {""}, {"crluri2", KW_CRLURI2}, {"leftcert", KW_LEFTCERT,}, - {"rightrsasigkey", KW_RIGHTRSASIGKEY}, + {""}, {"leftsubnet", KW_LEFTSUBNET}, - {"reauth", KW_REAUTH}, + {"crlcheckinterval", KW_CRLCHECKINTERVAL}, {"leftsendcert", KW_LEFTSENDCERT}, {"leftprotoport", KW_LEFTPROTOPORT}, {""}, {"right", KW_RIGHT}, - {"charondebug", KW_CHARONDEBUG}, - {"ocspuri", KW_OCSPURI}, + {""}, {""}, {"ike", KW_IKE}, {"rightcert", KW_RIGHTCERT}, {"klipsdebug", KW_KLIPSDEBUG}, @@ -163,78 +157,95 @@ static const struct kw_entry wordlist[] = {"plutostart", KW_PLUTOSTART}, {"ikelifetime", KW_IKELIFETIME}, {"keylife", KW_KEYLIFE}, - {"ocspuri2", KW_OCSPURI2}, - {"type", KW_TYPE}, + {""}, {""}, {"keep_alive", KW_KEEP_ALIVE}, {"keyexchange", KW_KEYEXCHANGE}, + {""}, {""}, {""}, + {"interfaces", KW_INTERFACES}, {""}, - {"prepluto", KW_PREPLUTO}, + {"leftallowany", KW_LEFTALLOWANY}, + {"leftrsasigkey", KW_LEFTRSASIGKEY}, {""}, - {"interfaces", KW_INTERFACES}, - {"overridemtu", KW_OVERRIDEMTU}, - {"crluri1", KW_CRLURI}, - {""}, {""}, {"leftgroups", KW_LEFTGROUPS}, {"leftid", KW_LEFTID}, - {""}, + {"crluri1", KW_CRLURI}, {"ldapbase", KW_LDAPBASE}, {"lefthostaccess", KW_LEFTHOSTACCESS}, - {"modeconfig", KW_MODECONFIG}, - {"leftca", KW_LEFTCA}, + {"rekey", KW_REKEY}, + {""}, {"pkcs11module", KW_PKCS11MODULE}, - {"nat_traversal", KW_NAT_TRAVERSAL}, - {"uniqueids", KW_UNIQUEIDS}, + {"rightallowany", KW_RIGHTALLOWANY}, + {"rightrsasigkey", KW_RIGHTRSASIGKEY}, {"pkcs11keepstate", KW_PKCS11KEEPSTATE}, {"rightgroups", KW_RIGHTGROUPS}, {"rightid", KW_RIGHTID}, {"esp", KW_ESP}, - {"postpluto", KW_POSTPLUTO}, + {"uniqueids", KW_UNIQUEIDS}, {"righthostaccess", KW_RIGHTHOSTACCESS}, - {"charonstart", KW_CHARONSTART}, - {"rightca", KW_RIGHTCA}, - {"ocspuri1", KW_OCSPURI}, + {"leftca", KW_LEFTCA}, + {"ocspuri", KW_OCSPURI}, + {"nat_traversal", KW_NAT_TRAVERSAL}, {"dpdaction", KW_DPDACTION}, + {"modeconfig", KW_MODECONFIG}, + {"overridemtu", KW_OVERRIDEMTU}, + {""}, + {"ocspuri2", KW_OCSPURI2}, + {""}, {""}, {""}, + {"rightca", KW_RIGHTCA}, + {"prepluto", KW_PREPLUTO}, + {"type", KW_TYPE}, {""}, {"eapdir", KW_EAPDIR}, - {"hidetos", KW_HIDETOS}, - {"eap", KW_EAP}, - {""}, {""}, - {"pkcs11proxy", KW_PKCS11PROXY}, {"dumpdir", KW_DUMPDIR}, + {"eap", KW_EAP}, {""}, {""}, - {"xauth", KW_XAUTH}, - {""}, {""}, - {"nocrsend", KW_NOCRSEND}, - {"also", KW_ALSO}, - {""}, {""}, {""}, - {"ldaphost", KW_LDAPHOST}, - {""}, {""}, - {"authby", KW_AUTHBY}, + {"reauth", KW_REAUTH}, {""}, - {"dpddelay", KW_DPDDELAY}, - {"auth", KW_AUTH}, - {""}, {""}, {""}, - {"compress", KW_COMPRESS}, - {"auto", KW_AUTO}, - {""}, {""}, {""}, + {"ldaphost", KW_LDAPHOST}, + {""}, {""}, {""}, {""}, {"fragicmp", KW_FRAGICMP}, {""}, {""}, - {"keyingtries", KW_KEYINGTRIES}, + {"charondebug", KW_CHARONDEBUG}, {""}, {"pfsgroup", KW_PFSGROUP}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {"keyingtries", KW_KEYINGTRIES}, + {""}, + {"ocspuri1", KW_OCSPURI}, {""}, {"dpdtimeout", KW_DPDTIMEOUT}, + {""}, {""}, {""}, {""}, {""}, + {"pkcs11proxy", KW_PKCS11PROXY}, + {""}, + {"nocrsend", KW_NOCRSEND}, + {""}, {""}, {""}, {""}, {""}, + {"pkcs11initargs", KW_PKCS11INITARGS}, + {""}, {"cacert", KW_CACERT}, + {""}, + {"packetdefault", KW_PACKETDEFAULT}, + {"also", KW_ALSO}, {""}, {""}, {""}, - {"strictcrlpolicy", KW_STRICTCRLPOLICY}, + {"dpddelay", KW_DPDDELAY}, + {"postpluto", KW_POSTPLUTO}, + {""}, + {"charonstart", KW_CHARONSTART}, + {"hidetos", KW_HIDETOS}, + {"compress", KW_COMPRESS}, + {""}, {""}, {""}, {""}, + {"pfs", KW_PFS}, {""}, {""}, - {"packetdefault", KW_PACKETDEFAULT}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {"authby", KW_AUTHBY}, + {""}, {""}, + {"auto", KW_AUTO}, + {""}, {""}, {""}, {""}, {""}, + {"strictcrlpolicy", KW_STRICTCRLPOLICY}, + {""}, {""}, {""}, {"cachecrls", KW_CACHECRLS}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {"pfs", KW_PFS} + {"xauth", KW_XAUTH}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, + {"auth", KW_AUTH} }; #ifdef __GNUC__ diff --git a/src/starter/keywords.h b/src/starter/keywords.h index 08d50fea0..8f5108ad8 100644 --- a/src/starter/keywords.h +++ b/src/starter/keywords.h @@ -25,9 +25,9 @@ typedef enum { KW_CHARONSTART, KW_PLUTOSTART, - /* pluto/charon keywords */ + /* pluto/charon keywords */ KW_PLUTODEBUG, - KW_CHARONDEBUG, + KW_CHARONDEBUG, KW_PREPLUTO, KW_POSTPLUTO, KW_UNIQUEIDS, @@ -41,6 +41,7 @@ typedef enum { KW_VIRTUAL_PRIVATE, KW_EAPDIR, KW_PKCS11MODULE, + KW_PKCS11INITARGS, KW_PKCS11KEEPSTATE, KW_PKCS11PROXY, @@ -112,6 +113,7 @@ typedef enum { KW_NATIP, KW_FIREWALL, KW_HOSTACCESS, + KW_ALLOWANY, KW_UPDOWN, KW_ID, KW_RSASIGKEY, @@ -134,6 +136,7 @@ typedef enum { KW_LEFTNATIP, KW_LEFTFIREWALL, KW_LEFTHOSTACCESS, + KW_LEFTALLOWANY, KW_LEFTUPDOWN, KW_LEFTID, KW_LEFTRSASIGKEY, @@ -155,6 +158,7 @@ typedef enum { KW_RIGHTNATIP, KW_RIGHTFIREWALL, KW_RIGHTHOSTACCESS, + KW_RIGHTALLOWANY, KW_RIGHTUPDOWN, KW_RIGHTID, KW_RIGHTRSASIGKEY, diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt index 0f943fc3c..573a2389a 100644 --- a/src/starter/keywords.txt +++ b/src/starter/keywords.txt @@ -50,6 +50,7 @@ virtual_private, KW_VIRTUAL_PRIVATE eap, KW_EAP eapdir, KW_EAPDIR pkcs11module, KW_PKCS11MODULE +pkcs11initargs, KW_PKCS11INITARGS pkcs11keepstate, KW_PKCS11KEEPSTATE pkcs11proxy, KW_PKCS11PROXY keyexchange, KW_KEYEXCHANGE @@ -91,6 +92,7 @@ leftsourceip, KW_LEFTSOURCEIP leftnatip, KW_LEFTNATIP leftfirewall, KW_LEFTFIREWALL lefthostaccess, KW_LEFTHOSTACCESS +leftallowany, KW_LEFTALLOWANY leftupdown, KW_LEFTUPDOWN leftid, KW_LEFTID leftrsasigkey, KW_LEFTRSASIGKEY @@ -107,6 +109,7 @@ rightsourceip, KW_RIGHTSOURCEIP rightnatip, KW_RIGHTNATIP rightfirewall, KW_RIGHTFIREWALL righthostaccess, KW_RIGHTHOSTACCESS +rightallowany, KW_RIGHTALLOWANY rightupdown, KW_RIGHTUPDOWN rightid, KW_RIGHTID rightrsasigkey, KW_RIGHTRSASIGKEY diff --git a/src/starter/starter.8 b/src/starter/starter.8 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/starter/starter.8 diff --git a/src/starter/starter.c b/src/starter/starter.c index 0bf1d7a71..3cf7017fd 100644 --- a/src/starter/starter.c +++ b/src/starter/starter.c @@ -237,9 +237,13 @@ int main (int argc, char **argv) } cfg = confread_load(CONFIG_FILE); - if (!cfg) + if (cfg == NULL || cfg->err > 0) { - plog("unable to start strongSwan -- errors in config"); + plog("unable to start strongSwan -- fatal errors in config"); + if (cfg) + { + confread_free(cfg); + } exit(1); } @@ -276,6 +280,7 @@ int main (int argc, char **argv) dup2(fnull, STDERR_FILENO); close(fnull); } + setsid(); } break; case -1: @@ -372,7 +377,7 @@ int main (int argc, char **argv) ); new_cfg = confread_load(CONFIG_FILE); - if (new_cfg) + if (new_cfg->err + new_cfg->non_fatal_err == 0) { /* Switch to new config. New conn will be loaded below */ if (!starter_cmp_defaultroute(&new_cfg->defaultroute @@ -465,7 +470,8 @@ int main (int argc, char **argv) } else { - plog("can't reload config file: %s -- keeping old one"); + plog("can't reload config file due to errors -- keeping old one"); + confread_free(new_cfg); } _action_ &= ~FLAG_ACTION_UPDATE; last_reload = time(NULL); diff --git a/src/starter/starterwhack.c b/src/starter/starterwhack.c index 42328849a..e920fc7ee 100644 --- a/src/starter/starterwhack.c +++ b/src/starter/starterwhack.c @@ -170,6 +170,7 @@ set_whack_end(whack_end_t *w, starter_end_t *end) w->has_natip = end->has_natip; w->modecfg = end->modecfg; w->hostaccess = end->hostaccess; + w->allow_any = end->allow_any; w->sendcert = end->sendcert; w->updown = end->updown; w->host_port = IKE_UDP_PORT; diff --git a/src/stroke/Makefile.in b/src/stroke/Makefile.in index a32dc8b90..8ca5f0144 100644 --- a/src/stroke/Makefile.in +++ b/src/stroke/Makefile.in @@ -126,6 +126,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/whack/Makefile.in b/src/whack/Makefile.in index e9a7af85d..136ebc521 100644 --- a/src/whack/Makefile.in +++ b/src/whack/Makefile.in @@ -126,6 +126,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ diff --git a/src/whack/whack.h b/src/whack/whack.h index 49ef67995..91463b0dd 100644 --- a/src/whack/whack.h +++ b/src/whack/whack.h @@ -65,6 +65,7 @@ struct whack_end { bool has_natip; bool modecfg; bool hostaccess; + bool allow_any; certpolicy_t sendcert; char *updown; /* string */ u_int16_t host_port; /* host order */ |