diff options
Diffstat (limited to 'src/charon')
63 files changed, 4534 insertions, 2877 deletions
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 */ |