diff options
Diffstat (limited to 'src/libcharon/plugins/duplicheck')
-rw-r--r-- | src/libcharon/plugins/duplicheck/Makefile.in | 38 | ||||
-rw-r--r-- | src/libcharon/plugins/duplicheck/duplicheck_listener.c | 186 |
2 files changed, 155 insertions, 69 deletions
diff --git a/src/libcharon/plugins/duplicheck/Makefile.in b/src/libcharon/plugins/duplicheck/Makefile.in index 0577b25ac..d1b5dfbe6 100644 --- a/src/libcharon/plugins/duplicheck/Makefile.in +++ b/src/libcharon/plugins/duplicheck/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.3 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -17,6 +17,23 @@ VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -115,6 +132,11 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ SOURCES = $(libstrongswan_duplicheck_la_SOURCES) $(duplicheck_SOURCES) DIST_SOURCES = $(libstrongswan_duplicheck_la_SOURCES) \ $(duplicheck_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -131,6 +153,8 @@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ @@ -147,6 +171,7 @@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GPERF = @GPERF@ +GPRBUILD = @GPRBUILD@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -215,8 +240,6 @@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ attest_plugins = @attest_plugins@ -axis2c_CFLAGS = @axis2c_CFLAGS@ -axis2c_LIBS = @axis2c_LIBS@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -272,7 +295,6 @@ nm_ca_dir = @nm_ca_dir@ nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ -p_plugins = @p_plugins@ pcsclite_CFLAGS = @pcsclite_CFLAGS@ pcsclite_LIBS = @pcsclite_LIBS@ pdfdir = @pdfdir@ @@ -365,7 +387,6 @@ clean-noinstLTLIBRARIES: done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) - test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ @@ -373,6 +394,8 @@ install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) else :; fi; \ done; \ test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } @@ -398,8 +421,11 @@ libstrongswan-duplicheck.la: $(libstrongswan_duplicheck_la_OBJECTS) $(libstrongs $(libstrongswan_duplicheck_la_LINK) $(am_libstrongswan_duplicheck_la_rpath) $(libstrongswan_duplicheck_la_OBJECTS) $(libstrongswan_duplicheck_la_LIBADD) $(LIBS) install-ipsecPROGRAMS: $(ipsec_PROGRAMS) @$(NORMAL_INSTALL) - test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(ipsecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" || exit 1; \ + fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ diff --git a/src/libcharon/plugins/duplicheck/duplicheck_listener.c b/src/libcharon/plugins/duplicheck/duplicheck_listener.c index 1b0df1e8b..30a723d36 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_listener.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_listener.c @@ -60,8 +60,8 @@ struct private_duplicheck_listener_t { typedef struct { /** peer identity */ identification_t *id; - /** IKE_SA identifier */ - ike_sa_id_t *sa; + /** list of IKE_SA identifiers, ike_sa_id_t */ + linked_list_t *sas; } entry_t; /** @@ -70,7 +70,7 @@ typedef struct { static void entry_destroy(entry_t *this) { this->id->destroy(this->id); - this->sa->destroy(this->sa); + this->sas->destroy_offset(this->sas, offsetof(ike_sa_id_t, destroy)); free(this); } @@ -90,27 +90,101 @@ static bool equals(identification_t *a, identification_t *b) return a->equals(a, b); } -METHOD(listener_t, ike_rekey, bool, - private_duplicheck_listener_t *this, ike_sa_t *old, ike_sa_t *new) +/** + * Put an IKE_SA identifier to hashtable + */ +static void put(hashtable_t *table, identification_t *id, ike_sa_id_t *sa) { - identification_t *id; - ike_sa_id_t *sa; entry_t *entry; - sa = new->get_id(new); - id = new->get_other_id(new); + entry = table->get(table, id); + if (!entry) + { + INIT(entry, + .id = id->clone(id), + .sas = linked_list_create(), + ); + table->put(table, entry->id, entry); + } + entry->sas->insert_last(entry->sas, sa->clone(sa)); +} - INIT(entry, - .id = id->clone(id), - .sa = sa->clone(sa), - ); - this->mutex->lock(this->mutex); - entry = this->active->put(this->active, entry->id, entry); - this->mutex->unlock(this->mutex); +/** + * Purge an entry from table if it has no IKE_SA identifiers + */ +static void remove_if_empty(hashtable_t *table, entry_t *entry) +{ + if (entry->sas->get_count(entry->sas) == 0) + { + entry = table->remove(table, entry->id); + if (entry) + { + entry_destroy(entry); + } + } +} + +/** + * Remove the first entry found in the table for the given id + */ +static ike_sa_id_t *remove_first(hashtable_t *table, identification_t *id) +{ + ike_sa_id_t *sa = NULL; + entry_t *entry; + + entry = table->get(table, id); + if (entry) + { + entry->sas->remove_first(entry->sas, (void**)&sa); + remove_if_empty(table, entry); + } + return sa; +} + +/** + * Remove a specific IKE_SA ID for the given identity + */ +static bool remove_specific(hashtable_t *table, identification_t *id, + ike_sa_id_t *sa) +{ + enumerator_t *enumerator; + bool found = FALSE; + entry_t *entry; + ike_sa_id_t *current; + + entry = table->get(table, id); if (entry) { - entry_destroy(entry); + enumerator = entry->sas->create_enumerator(entry->sas); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (sa->equals(sa, current)) + { + entry->sas->remove_at(entry->sas, enumerator); + current->destroy(current); + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + if (found) + { + remove_if_empty(table, entry); + } } + return found; +} + +METHOD(listener_t, ike_rekey, bool, + private_duplicheck_listener_t *this, ike_sa_t *old, ike_sa_t *new) +{ + this->mutex->lock(this->mutex); + + remove_specific(this->active, old->get_other_id(old), old->get_id(old)); + put(this->active, new->get_other_id(new), new->get_id(new)); + + this->mutex->unlock(this->mutex); + return TRUE; } @@ -119,58 +193,41 @@ METHOD(listener_t, ike_updown, bool, { identification_t *id; ike_sa_id_t *sa; - entry_t *entry; - job_t *job; - sa = ike_sa->get_id(ike_sa); id = ike_sa->get_other_id(ike_sa); + this->mutex->lock(this->mutex); if (up) { - INIT(entry, - .id = id->clone(id), - .sa = sa->clone(sa), - ); - this->mutex->lock(this->mutex); - entry = this->active->put(this->active, entry->id, entry); - this->mutex->unlock(this->mutex); - if (entry) + /* another IKE_SA for this identity active? */ + sa = remove_first(this->active, id); + if (sa) { DBG1(DBG_CFG, "detected duplicate IKE_SA for '%Y', " "triggering delete for old IKE_SA", id); - job = (job_t*)delete_ike_sa_job_create(entry->sa, TRUE); - this->mutex->lock(this->mutex); - entry = this->checking->put(this->checking, entry->id, entry); - this->mutex->unlock(this->mutex); - lib->processor->queue_job(lib->processor, job); - if (entry) - { - entry_destroy(entry); - } + put(this->checking, id, sa); + lib->processor->queue_job(lib->processor, + (job_t*)delete_ike_sa_job_create(sa, TRUE)); + sa->destroy(sa); } + /* register IKE_SA as the new active */ + sa = ike_sa->get_id(ike_sa); + put(this->active, id, sa); } else { - this->mutex->lock(this->mutex); - entry = this->checking->remove(this->checking, id); - this->mutex->unlock(this->mutex); - if (entry) + sa = ike_sa->get_id(ike_sa); + /* check if closing an IKE_SA currently in checking state */ + if (remove_specific(this->checking, id, sa)) { DBG1(DBG_CFG, "delete for duplicate IKE_SA '%Y' timed out, " "keeping new IKE_SA", id); - entry_destroy(entry); - } - else - { - this->mutex->lock(this->mutex); - entry = this->active->remove(this->active, id); - this->mutex->unlock(this->mutex); - if (entry) - { - entry_destroy(entry); - } } + /* check normal close of IKE_SA */ + remove_specific(this->active, id, sa); } + this->mutex->unlock(this->mutex); + return TRUE; } @@ -181,29 +238,32 @@ METHOD(listener_t, message_hook, bool, if (incoming && plain && !message->get_request(message)) { identification_t *id; - entry_t *entry; + ike_sa_id_t *sa; id = ike_sa->get_other_id(ike_sa); + sa = ike_sa->get_id(ike_sa); + this->mutex->lock(this->mutex); - entry = this->checking->remove(this->checking, id); - this->mutex->unlock(this->mutex); - if (entry) + if (remove_specific(this->checking, id, sa)) { DBG1(DBG_CFG, "got a response on a duplicate IKE_SA for '%Y', " "deleting new IKE_SA", id); charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP); - entry_destroy(entry); - this->mutex->lock(this->mutex); - entry = this->active->remove(this->active, id); - this->mutex->unlock(this->mutex); - if (entry) + sa = remove_first(this->active, id); + if (sa) { lib->processor->queue_job(lib->processor, - (job_t*)delete_ike_sa_job_create(entry->sa, TRUE)); - entry_destroy(entry); + (job_t*)delete_ike_sa_job_create(sa, TRUE)); + sa->destroy(sa); } + this->mutex->unlock(this->mutex); + this->notify->send(this->notify, id); } + else + { + this->mutex->unlock(this->mutex); + } } return TRUE; } |