diff options
Diffstat (limited to 'src/libcharon')
179 files changed, 3522 insertions, 1486 deletions
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 8461d6230..3fcaedc3b 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -184,6 +184,15 @@ if USE_ME sa/ikev2/tasks/ike_me.c sa/ikev2/tasks/ike_me.h endif +if STATIC_PLUGIN_CONSTRUCTORS +BUILT_SOURCES = $(srcdir)/plugin_constructors.c +CLEANFILES = $(srcdir)/plugin_constructors.c + +$(srcdir)/plugin_constructors.c: $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py + $(AM_V_GEN) \ + $(PYTHON) $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py ${c_plugins} > $@ +endif + # build optional plugins ######################## diff --git a/src/libcharon/Makefile.in b/src/libcharon/Makefile.in index 8f6dc89a3..ef9ffd39b 100644 --- a/src/libcharon/Makefile.in +++ b/src/libcharon/Makefile.in @@ -934,6 +934,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -956,6 +957,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ @@ -1167,6 +1169,8 @@ libcharon_la_LIBADD = \ $(am__append_141) $(am__append_143) $(am__append_145) \ $(am__append_147) EXTRA_DIST = Android.mk +@STATIC_PLUGIN_CONSTRUCTORS_TRUE@BUILT_SOURCES = $(srcdir)/plugin_constructors.c +@STATIC_PLUGIN_CONSTRUCTORS_TRUE@CLEANFILES = $(srcdir)/plugin_constructors.c @MONOLITHIC_FALSE@SUBDIRS = . $(am__append_6) $(am__append_8) \ @MONOLITHIC_FALSE@ $(am__append_10) $(am__append_12) \ @MONOLITHIC_FALSE@ $(am__append_14) $(am__append_16) \ @@ -1240,7 +1244,8 @@ EXTRA_DIST = Android.mk @MONOLITHIC_TRUE@ $(am__append_138) $(am__append_140) \ @MONOLITHIC_TRUE@ $(am__append_142) $(am__append_144) \ @MONOLITHIC_TRUE@ $(am__append_146) . tests -all: all-recursive +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj @@ -2095,14 +2100,16 @@ distdir: $(DISTFILES) fi; \ done check-am: all-am -check: check-recursive +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(LTLIBRARIES) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(ipseclibdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: install-recursive +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive @@ -2124,6 +2131,7 @@ install-strip: mostlyclean-generic: clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -2170,6 +2178,7 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \ @@ -2241,7 +2250,8 @@ ps-am: uninstall-am: uninstall-ipseclibLTLIBRARIES -.MAKE: $(am__recursive_targets) install-am install-strip +.MAKE: $(am__recursive_targets) all check install install-am \ + install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-ipseclibLTLIBRARIES \ @@ -2264,6 +2274,10 @@ uninstall-am: uninstall-ipseclibLTLIBRARIES daemon.lo : $(top_builddir)/config.status +@STATIC_PLUGIN_CONSTRUCTORS_TRUE@$(srcdir)/plugin_constructors.c: $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py +@STATIC_PLUGIN_CONSTRUCTORS_TRUE@ $(AM_V_GEN) \ +@STATIC_PLUGIN_CONSTRUCTORS_TRUE@ $(PYTHON) $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py ${c_plugins} > $@ + @MONOLITHIC_TRUE@@USE_SIMAKA_TRUE@ # otherwise this library is linked to both the eap_aka and the eap_sim plugin @MONOLITHIC_TRUE@@USE_TLS_TRUE@ # otherwise this library is linked to eap_tls diff --git a/src/libcharon/attributes/attribute_manager.c b/src/libcharon/attributes/attribute_manager.c index 2ab7ed118..3a4a21a02 100644 --- a/src/libcharon/attributes/attribute_manager.c +++ b/src/libcharon/attributes/attribute_manager.c @@ -237,14 +237,14 @@ typedef struct { linked_list_t *vips; } initiator_enumerator_t; -/** - * Enumerator implementation for initiator attributes - */ -static bool initiator_enumerate(initiator_enumerator_t *this, - attribute_handler_t **handler, - configuration_attribute_type_t *type, - chunk_t *value) +METHOD(enumerator_t, initiator_enumerate, bool, + initiator_enumerator_t *this, va_list args) { + configuration_attribute_type_t *type; + attribute_handler_t **handler; + chunk_t *value; + + VA_ARGS_VGET(args, handler, type, value); /* enumerate inner attributes using outer handler enumerator */ while (!this->inner || !this->inner->enumerate(this->inner, type, value)) { @@ -261,10 +261,8 @@ static bool initiator_enumerate(initiator_enumerator_t *this, return TRUE; } -/** - * Cleanup function of initiator attribute enumerator - */ -static void initiator_destroy(initiator_enumerator_t *this) +METHOD(enumerator_t, initiator_destroy, void, + initiator_enumerator_t *this) { this->this->lock->unlock(this->this->lock); this->outer->destroy(this->outer); @@ -281,8 +279,9 @@ METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)initiator_enumerate, - .destroy = (void*)initiator_destroy, + .enumerate = enumerator_enumerate_default, + .venumerate = _initiator_enumerate, + .destroy = _initiator_destroy, }, .this = this, .ike_sa = ike_sa, diff --git a/src/libcharon/attributes/mem_pool.c b/src/libcharon/attributes/mem_pool.c index a2b7c2803..e1a9a6dce 100644 --- a/src/libcharon/attributes/mem_pool.c +++ b/src/libcharon/attributes/mem_pool.c @@ -512,10 +512,15 @@ typedef struct { } lease_enumerator_t; METHOD(enumerator_t, lease_enumerate, bool, - lease_enumerator_t *this, identification_t **id, host_t **addr, bool *online) + lease_enumerator_t *this, va_list args) { - u_int *offset; + identification_t **id; unique_lease_t *lease; + host_t **addr; + u_int *offset; + bool *online; + + VA_ARGS_VGET(args, id, addr, online); DESTROY_IF(this->addr); this->addr = NULL; @@ -570,7 +575,8 @@ METHOD(mem_pool_t, create_lease_enumerator, enumerator_t*, this->mutex->lock(this->mutex); INIT(enumerator, .public = { - .enumerate = (void*)_lease_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _lease_enumerate, .destroy = _lease_enumerator_destroy, }, .pool = this, diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c index f4bba872f..77a910197 100644 --- a/src/libcharon/bus/bus.c +++ b/src/libcharon/bus/bus.c @@ -207,20 +207,20 @@ static inline void register_logger(private_bus_t *this, debug_t group, } } -/** - * Find the log level of the first registered logger that implements log or - * vlog (or both). - */ -static bool find_max_levels(log_entry_t *entry, debug_t *group, level_t *level, - level_t *vlevel) +CALLBACK(find_max_levels, bool, + log_entry_t *entry, va_list args) { + level_t *level, *vlevel; + debug_t group; + + VA_ARGS_VGET(args, group, level, vlevel); if (entry->logger->log && *level == LEVEL_SILENT) { - *level = entry->levels[*group]; + *level = entry->levels[group]; } if (entry->logger->vlog && *vlevel == LEVEL_SILENT) { - *vlevel = entry->levels[*group]; + *vlevel = entry->levels[group]; } return *level > LEVEL_SILENT && *vlevel > LEVEL_SILENT; } @@ -258,8 +258,8 @@ static inline void unregister_logger(private_bus_t *this, logger_t *logger) loggers = this->loggers[group]; loggers->remove(loggers, found, NULL); - loggers->find_first(loggers, (linked_list_match_t)find_max_levels, - NULL, &group, &level, &vlevel); + loggers->find_first(loggers, find_max_levels, NULL, group, + &level, &vlevel); set_level(&this->max_level[group], level); set_level(&this->max_vlevel[group], vlevel); } @@ -330,11 +330,12 @@ typedef struct { va_list args; } log_data_t; -/** - * logger->log() invocation as a invoke_function callback - */ -static void log_cb(log_entry_t *entry, log_data_t *data) +CALLBACK(log_cb, void, + log_entry_t *entry, va_list args) { + log_data_t *data; + + VA_ARGS_VGET(args, data); if (entry->logger->log && entry->levels[data->group] >= data->level) { entry->logger->log(entry->logger, data->group, data->level, @@ -342,11 +343,12 @@ static void log_cb(log_entry_t *entry, log_data_t *data) } } -/** - * logger->vlog() invocation as a invoke_function callback - */ -static void vlog_cb(log_entry_t *entry, log_data_t *data) +CALLBACK(vlog_cb, void, + log_entry_t *entry, va_list args) { + log_data_t *data; + + VA_ARGS_VGET(args, data); if (entry->logger->vlog && entry->levels[data->group] >= data->level) { va_list copy; @@ -405,8 +407,7 @@ METHOD(bus_t, vlog, void, } if (len > 0) { - loggers->invoke_function(loggers, (linked_list_invoke_t)log_cb, - &data); + loggers->invoke_function(loggers, log_cb, &data); } if (data.message != buf) { @@ -422,7 +423,7 @@ METHOD(bus_t, vlog, void, data.message = format; va_copy(data.args, args); - loggers->invoke_function(loggers, (linked_list_invoke_t)vlog_cb, &data); + loggers->invoke_function(loggers, vlog_cb, &data); va_end(data.args); } diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index 79f1d9fee..4f154df9b 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -265,20 +265,24 @@ static void peer_enum_destroy(peer_data_t *data) free(data); } -/** - * convert enumerator value from match_entry to config - */ -static bool peer_enum_filter(linked_list_t *configs, - match_entry_t **in, peer_cfg_t **out) +CALLBACK(peer_enum_filter, bool, + linked_list_t *configs, enumerator_t *orig, va_list args) { - *out = (*in)->cfg; - return TRUE; + match_entry_t *entry; + peer_cfg_t **out; + + VA_ARGS_VGET(args, out); + + if (orig->enumerate(orig, &entry)) + { + *out = entry->cfg; + return TRUE; + } + return FALSE; } -/** - * Clean up temporary config list - */ -static void peer_enum_filter_destroy(linked_list_t *configs) +CALLBACK(peer_enum_filter_destroy, void, + linked_list_t *configs) { match_entry_t *entry; @@ -379,8 +383,8 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, helper->destroy(helper); return enumerator_create_filter(configs->create_enumerator(configs), - (void*)peer_enum_filter, configs, - (void*)peer_enum_filter_destroy); + peer_enum_filter, configs, + peer_enum_filter_destroy); } METHOD(backend_manager_t, get_peer_cfg_by_name, peer_cfg_t*, diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 3c6dd5198..ec2a12431 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -1,6 +1,6 @@ /* + * Copyright (C) 2008-2017 Tobias Brunner * Copyright (C) 2016 Andreas Steffen - * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * HSR Hochschule fuer Technik Rapperswil @@ -54,6 +54,11 @@ struct private_child_cfg_t { char *name; /** + * Options + */ + child_cfg_option_t options; + + /** * list for all proposals */ linked_list_t *proposals; @@ -74,11 +79,6 @@ struct private_child_cfg_t { char *updown; /** - * allow host access - */ - bool hostaccess; - - /** * Mode to propose for a initiated CHILD: tunnel/transport */ ipsec_mode_t mode; @@ -104,11 +104,6 @@ struct private_child_cfg_t { lifetime_cfg_t lifetime; /** - * enable IPComp - */ - bool use_ipcomp; - - /** * Inactivity timeout */ uint32_t inactivity; @@ -144,21 +139,6 @@ struct private_child_cfg_t { char *interface; /** - * set up IPsec transport SA in MIPv6 proxy mode - */ - bool proxy_mode; - - /** - * enable installation and removal of kernel IPsec policies - */ - bool install_policy; - - /** - * Install outbound FWD policies - */ - bool fwd_out_policy; - - /** * anti-replay window size */ uint32_t replay_window; @@ -170,6 +150,12 @@ METHOD(child_cfg_t, get_name, char*, return this->name; } +METHOD(child_cfg_t, has_option, bool, + private_child_cfg_t *this, child_cfg_option_t option) +{ + return this->options & option; +} + METHOD(child_cfg_t, add_proposal, void, private_child_cfg_t *this, proposal_t *proposal) { @@ -179,8 +165,12 @@ METHOD(child_cfg_t, add_proposal, void, } } -static bool match_proposal(proposal_t *item, proposal_t *proposal) +CALLBACK(match_proposal, bool, + proposal_t *item, va_list args) { + proposal_t *proposal; + + VA_ARGS_VGET(args, proposal); return item->equals(item, proposal); } @@ -199,8 +189,7 @@ METHOD(child_cfg_t, get_proposals, linked_list_t*, { current->strip_dh(current, MODP_NONE); } - if (proposals->find_first(proposals, (linked_list_match_t)match_proposal, - NULL, current) == SUCCESS) + if (proposals->find_first(proposals, match_proposal, NULL, current)) { current->destroy(current); continue; @@ -311,8 +300,9 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, { if (hosts && hosts->get_count(hosts)) { /* set hosts if TS is dynamic or as initiator in transport mode */ - bool dynamic = ts1->is_dynamic(ts1); - if (dynamic || (this->mode == MODE_TRANSPORT && !this->proxy_mode && + bool dynamic = ts1->is_dynamic(ts1), + proxy_mode = has_option(this, OPT_PROXY_MODE); + if (dynamic || (this->mode == MODE_TRANSPORT && !proxy_mode && !supplied)) { e2 = hosts->create_enumerator(hosts); @@ -428,12 +418,6 @@ METHOD(child_cfg_t, get_updown, char*, return this->updown; } -METHOD(child_cfg_t, get_hostaccess, bool, - private_child_cfg_t *this) -{ - return this->hostaccess; -} - /** * Applies jitter to the rekey value. Returns the new rekey value. * Note: The distribution of random values is not perfect, but it @@ -508,12 +492,6 @@ METHOD(child_cfg_t, get_dh_group, diffie_hellman_group_t, return dh_group; } -METHOD(child_cfg_t, use_ipcomp, bool, - private_child_cfg_t *this) -{ - return this->use_ipcomp; -} - METHOD(child_cfg_t, get_inactivity, uint32_t, private_child_cfg_t *this) { @@ -562,24 +540,6 @@ METHOD(child_cfg_t, set_replay_window, void, this->replay_window = replay_window; } -METHOD(child_cfg_t, use_proxy_mode, bool, - private_child_cfg_t *this) -{ - return this->proxy_mode; -} - -METHOD(child_cfg_t, install_policy, bool, - private_child_cfg_t *this) -{ - return this->install_policy; -} - -METHOD(child_cfg_t, install_fwd_out_policy, bool, - private_child_cfg_t *this) -{ - return this->fwd_out_policy; -} - #define LT_PART_EQUALS(a, b) ({ a.life == b.life && a.rekey == b.rekey && a.jitter == b.jitter; }) #define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); }) @@ -611,13 +571,12 @@ METHOD(child_cfg_t, equals, bool, { return FALSE; } - return this->hostaccess == other->hostaccess && + return this->options == other->options && this->mode == other->mode && this->start_action == other->start_action && this->dpd_action == other->dpd_action && this->close_action == other->close_action && LIFETIME_EQUALS(this->lifetime, other->lifetime) && - this->use_ipcomp == other->use_ipcomp && this->inactivity == other->inactivity && this->reqid == other->reqid && this->mark_in.value == other->mark_in.value && @@ -627,9 +586,6 @@ METHOD(child_cfg_t, equals, bool, this->tfc == other->tfc && this->manual_prio == other->manual_prio && this->replay_window == other->replay_window && - this->proxy_mode == other->proxy_mode && - this->install_policy == other->install_policy && - this->fwd_out_policy == other->fwd_out_policy && streq(this->updown, other->updown) && streq(this->interface, other->interface); } @@ -672,14 +628,12 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .get_proposals = _get_proposals, .select_proposal = _select_proposal, .get_updown = _get_updown, - .get_hostaccess = _get_hostaccess, .get_mode = _get_mode, .get_start_action = _get_start_action, .get_dpd_action = _get_dpd_action, .get_close_action = _get_close_action, .get_lifetime = _get_lifetime, .get_dh_group = _get_dh_group, - .use_ipcomp = _use_ipcomp, .get_inactivity = _get_inactivity, .get_reqid = _get_reqid, .get_mark = _get_mark, @@ -688,19 +642,16 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .get_interface = _get_interface, .get_replay_window = _get_replay_window, .set_replay_window = _set_replay_window, - .use_proxy_mode = _use_proxy_mode, - .install_policy = _install_policy, - .install_fwd_out_policy = _install_fwd_out_policy, + .has_option = _has_option, .equals = _equals, .get_ref = _get_ref, .destroy = _destroy, }, .name = strdup(name), + .options = data->options, .updown = strdupnull(data->updown), - .hostaccess = data->hostaccess, .reqid = data->reqid, .mode = data->mode, - .proxy_mode = data->proxy_mode, .start_action = data->start_action, .dpd_action = data->dpd_action, .close_action = data->close_action, @@ -708,12 +659,9 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .mark_out = data->mark_out, .lifetime = data->lifetime, .inactivity = data->inactivity, - .use_ipcomp = data->ipcomp, .tfc = data->tfc, .manual_prio = data->priority, .interface = strdupnull(data->interface), - .install_policy = !data->suppress_policies, - .fwd_out_policy = data->fwd_out_policies, .refcount = 1, .proposals = linked_list_create(), .my_ts = linked_list_create(), diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index b85bfd9bc..a102c459c 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -1,6 +1,6 @@ /* + * Copyright (C) 2008-2017 Tobias Brunner * Copyright (C) 2016 Andreas Steffen - * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * HSR Hochschule fuer Technik Rapperswil @@ -25,6 +25,7 @@ #define CHILD_CFG_H_ typedef enum action_t action_t; +typedef enum child_cfg_option_t child_cfg_option_t; typedef struct child_cfg_t child_cfg_t; typedef struct child_cfg_create_t child_cfg_create_t; @@ -147,13 +148,6 @@ struct child_cfg_t { char* (*get_updown)(child_cfg_t *this); /** - * Should we allow access to the local host (gateway)? - * - * @return value of hostaccess flag - */ - bool (*get_hostaccess) (child_cfg_t *this); - - /** * Get the lifetime configuration of a CHILD_SA. * * The rekey limits automatically contain a jitter to avoid simultaneous @@ -203,14 +197,6 @@ struct child_cfg_t { diffie_hellman_group_t (*get_dh_group)(child_cfg_t *this); /** - * Check whether IPComp should be used, if the other peer supports it. - * - * @return TRUE, if IPComp should be used - * FALSE, otherwise - */ - bool (*use_ipcomp)(child_cfg_t *this); - - /** * Get the inactivity timeout value. * * @return inactivity timeout in s @@ -263,33 +249,17 @@ struct child_cfg_t { /** * Set anti-replay window size * - * @param window anti-replay window size + * @param window anti-replay window size */ void (*set_replay_window)(child_cfg_t *this, uint32_t window); /** - * Check whether IPsec transport SA should be set up in proxy mode. - * - * @return TRUE, if proxy mode should be used - * FALSE, otherwise - */ - bool (*use_proxy_mode)(child_cfg_t *this); - - /** - * Check whether IPsec policies should be installed in the kernel. - * - * @return TRUE, if IPsec kernel policies should be installed - * FALSE, otherwise - */ - bool (*install_policy)(child_cfg_t *this); - - /** - * Check whether outbound FWD IPsec policies should be installed. + * Check if an option flag is set. * - * @return TRUE, if outbound FWD policies should be installed - * FALSE, otherwise + * @param option option flag to check + * @return TRUE if option flag set, FALSE otherwise */ - bool (*install_fwd_out_policy)(child_cfg_t *this); + bool (*has_option)(child_cfg_t *this, child_cfg_option_t option); /** * Check if two child_cfg objects are equal. @@ -315,11 +285,39 @@ struct child_cfg_t { void (*destroy) (child_cfg_t *this); }; +/** + * Option flags that may be set on a child_cfg_t object + */ +enum child_cfg_option_t { + + /** Use IPsec transport proxy mode */ + OPT_PROXY_MODE = (1<<0), + + /** Use IPComp, if peer supports it */ + OPT_IPCOMP = (1<<1), + + /** Allow access to the local host */ + OPT_HOSTACCESS = (1<<2), + + /** Don't install any IPsec policies */ + OPT_NO_POLICIES = (1<<3), + + /** Install outbound FWD IPsec policies to bypass drop policies */ + OPT_FWD_OUT_POLICIES = (1<<4), + + /** Enable hardware offload, if supported by the IPsec backend */ + OPT_HW_OFFLOAD = (1<<5), + + /** Force 96-bit truncation for SHA-256 */ + OPT_SHA256_96 = (1<<6), +}; /** * Data passed to the constructor of a child_cfg_t object. */ struct child_cfg_create_t { + /** Options set for CHILD_SA */ + child_cfg_option_t options; /** Specific reqid to use for CHILD_SA, 0 for auto assignment */ uint32_t reqid; /** Optional inbound mark */ @@ -328,10 +326,6 @@ struct child_cfg_create_t { mark_t mark_out; /** Mode to propose for CHILD_SA */ ipsec_mode_t mode; - /** Use IPsec transport proxy mode */ - bool proxy_mode; - /** Use IPComp, if peer supports it */ - bool ipcomp; /** TFC padding size, 0 to disable, -1 to pad to PMTU */ uint32_t tfc; /** Optional manually-set IPsec policy priority */ @@ -350,12 +344,6 @@ struct child_cfg_create_t { action_t close_action; /** updown script to execute on up/down event (cloned) */ char *updown; - /** TRUE to allow access to the local host */ - bool hostaccess; - /** Don't install IPsec policies */ - bool suppress_policies; - /** Install outbound FWD IPsec policies to bypass drop policies */ - bool fwd_out_policies; }; /** diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index 480dd3720..93300781d 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -224,12 +224,12 @@ static u_int match(linked_list_t *hosts, linked_list_t *ranges, host_t *cand) if (ts->to_subnet(ts, &host, &mask)) { quality = max(quality, mask + 1); - host->destroy(host); } else { quality = max(quality, 1); } + host->destroy(host); } } enumerator->destroy(enumerator); diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index 4d37264f6..034996f60 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -47,14 +47,16 @@ enum ike_version_t { }; /** - * Proprietary IKEv1 fragmentation + * Proprietary IKEv1 fragmentation and IKEv2 fragmentation */ enum fragmentation_t { /** disable fragmentation */ FRAGMENTATION_NO, - /** enable fragmentation if supported by peer */ + /** announce support, but don't send any fragments */ + FRAGMENTATION_ACCEPT, + /** enable fragmentation, if supported by peer */ FRAGMENTATION_YES, - /** force use of fragmentation (even for the first message) */ + /** force use of fragmentation (even for the first message for IKEv1) */ FRAGMENTATION_FORCE, }; diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index 5d7ab076e..fcdd6fdeb 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -209,9 +209,12 @@ typedef struct { } child_cfgs_replace_enumerator_t; METHOD(enumerator_t, child_cfgs_replace_enumerate, bool, - child_cfgs_replace_enumerator_t *this, child_cfg_t **chd, bool *added) + child_cfgs_replace_enumerator_t *this, va_list args) { - child_cfg_t *child_cfg; + child_cfg_t *child_cfg, **chd; + bool *added; + + VA_ARGS_VGET(args, chd, added); if (!this->wrapped) { @@ -303,8 +306,9 @@ METHOD(peer_cfg_t, replace_child_cfgs, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_child_cfgs_replace_enumerate, - .destroy = (void*)_child_cfgs_replace_enumerator_destroy, + .enumerate = enumerator_enumerate_default, + .venumerate = _child_cfgs_replace_enumerate, + .destroy = _child_cfgs_replace_enumerator_destroy, }, .removed = removed, .added = added, @@ -336,8 +340,11 @@ METHOD(enumerator_t, child_cfg_enumerator_destroy, void, } METHOD(enumerator_t, child_cfg_enumerate, bool, - child_cfg_enumerator_t *this, child_cfg_t **chd) + child_cfg_enumerator_t *this, va_list args) { + child_cfg_t **chd; + + VA_ARGS_VGET(args, chd); return this->wrapped->enumerate(this->wrapped, chd); } @@ -348,8 +355,9 @@ METHOD(peer_cfg_t, create_child_cfg_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_child_cfg_enumerate, - .destroy = (void*)_child_cfg_enumerator_destroy, + .enumerate = enumerator_enumerate_default, + .venumerate = _child_cfg_enumerate, + .destroy = _child_cfg_enumerator_destroy, }, .mutex = this->mutex, .wrapped = this->child_cfgs->create_enumerator(this->child_cfgs), diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c index a2dc113a5..6c71f78d3 100644 --- a/src/libcharon/config/proposal.c +++ b/src/libcharon/config/proposal.c @@ -94,27 +94,31 @@ METHOD(proposal_t, add_algorithm, void, array_insert(this->transforms, ARRAY_TAIL, &entry); } -/** - * filter function for peer configs - */ -static bool alg_filter(uintptr_t type, entry_t **in, uint16_t *alg, - void **unused, uint16_t *key_size) +CALLBACK(alg_filter, bool, + uintptr_t type, enumerator_t *orig, va_list args) { - entry_t *entry = *in; + entry_t *entry; + uint16_t *alg, *key_size; - if (entry->type != type) - { - return FALSE; - } - if (alg) - { - *alg = entry->alg; - } - if (key_size) + VA_ARGS_VGET(args, alg, key_size); + + while (orig->enumerate(orig, &entry)) { - *key_size = entry->key_size; + if (entry->type != type) + { + continue; + } + if (alg) + { + *alg = entry->alg; + } + if (key_size) + { + *key_size = entry->key_size; + } + return TRUE; } - return TRUE; + return FALSE; } METHOD(proposal_t, create_enumerator, enumerator_t*, @@ -122,7 +126,7 @@ METHOD(proposal_t, create_enumerator, enumerator_t*, { return enumerator_create_filter( array_create_enumerator(this->transforms), - (void*)alg_filter, (void*)(uintptr_t)type, NULL); + alg_filter, (void*)(uintptr_t)type, NULL); } METHOD(proposal_t, get_algorithm, bool, diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index eadc10a6a..7c9f83d12 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -118,6 +118,13 @@ struct private_daemon_t { }; /** + * Register plugins if built statically + */ +#ifdef STATIC_PLUGIN_CONSTRUCTORS +#include "plugin_constructors.c" +#endif + +/** * One and only instance of the daemon. */ daemon_t *charon; @@ -275,13 +282,14 @@ static void logger_entry_unregister_destroy(logger_entry_t *this) logger_entry_destroy(this); } -/** - * Match a logger entry by target and whether it is a file or syslog logger - */ -static bool logger_entry_match(logger_entry_t *this, char *target, - logger_type_t *type) +CALLBACK(logger_entry_match, bool, + logger_entry_t *this, va_list args) { - return this->type == *type && streq(this->target, target); + logger_type_t type; + char *target; + + VA_ARGS_VGET(args, target, type); + return this->type == type && streq(this->target, target); } /** @@ -343,8 +351,8 @@ static logger_entry_t *get_logger_entry(char *target, logger_type_t type, { logger_entry_t *entry; - if (existing->find_first(existing, (void*)logger_entry_match, - (void**)&entry, target, &type) != SUCCESS) + if (!existing->find_first(existing, logger_entry_match, (void**)&entry, + target, type)) { INIT(entry, .target = strdup(target), diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 50dab9e38..6d850aac0 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -554,10 +554,10 @@ static payload_order_t aggressive_i_order[] = { {PLV1_CERTREQ, 0}, {PLV1_NOTIFY, 0}, {PLV1_VENDOR_ID, 0}, + {PLV1_HASH, 0}, {PLV1_NAT_D, 0}, {PLV1_NAT_D_DRAFT_00_03, 0}, {PLV1_SIGNATURE, 0}, - {PLV1_HASH, 0}, {PLV1_FRAGMENT, 0}, }; diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c index 09bfa2458..643fbc42f 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -190,8 +190,12 @@ struct keyid_enumerator_t { }; METHOD(enumerator_t, keyid_enumerate, bool, - keyid_enumerator_t *this, chunk_t *chunk) + keyid_enumerator_t *this, va_list args) { + chunk_t *chunk; + + VA_ARGS_VGET(args, chunk); + if (this->pos == NULL) { this->pos = this->full.ptr; @@ -224,7 +228,8 @@ METHOD(certreq_payload_t, create_keyid_enumerator, enumerator_t*, } INIT(enumerator, .public = { - .enumerate = (void*)_keyid_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _keyid_enumerate, .destroy = (void*)free, }, .full = this->data, diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index 584e6f22b..3634cd36c 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -306,8 +306,12 @@ typedef struct { } spi_enumerator_t; METHOD(enumerator_t, spis_enumerate, bool, - spi_enumerator_t *this, uint32_t *spi) + spi_enumerator_t *this, va_list args) { + uint32_t *spi; + + VA_ARGS_VGET(args, spi); + if (this->spis.len >= sizeof(*spi)) { memcpy(spi, this->spis.ptr, sizeof(*spi)); @@ -328,7 +332,8 @@ METHOD(delete_payload_t, create_spi_enumerator, enumerator_t*, } INIT(e, .public = { - .enumerate = (void*)_spis_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _spis_enumerate, .destroy = (void*)free, }, .spis = this->spis, diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index 8c3fc5933..923135da9 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -270,8 +270,12 @@ typedef struct { } type_enumerator_t; METHOD(enumerator_t, enumerate_types, bool, - type_enumerator_t *this, eap_type_t *type, uint32_t *vendor) + type_enumerator_t *this, va_list args) { + eap_type_t *type; + uint32_t *vendor; + + VA_ARGS_VGET(args, type, vendor); this->offset = extract_type(this->payload, this->offset, type, vendor); return this->offset; } @@ -289,7 +293,8 @@ METHOD(eap_payload_t, get_types, enumerator_t*, { INIT(enumerator, .public = { - .enumerate = (void*)_enumerate_types, + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate_types, .destroy = (void*)free, }, .payload = this, diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c index ea5af9eb8..3d736b25b 100644 --- a/src/libcharon/kernel/kernel_interface.c +++ b/src/libcharon/kernel/kernel_interface.c @@ -632,21 +632,18 @@ METHOD(kernel_interface_t, enable_udp_decap, bool, METHOD(kernel_interface_t, is_interface_usable, bool, private_kernel_interface_t *this, const char *iface) { - status_t expected; - if (!this->ifaces_filter) { return TRUE; } - expected = this->ifaces_exclude ? NOT_FOUND : SUCCESS; - return this->ifaces_filter->find_first(this->ifaces_filter, (void*)streq, - NULL, iface) == expected; + return this->ifaces_filter->find_first(this->ifaces_filter, + linked_list_match_str, NULL, iface) != this->ifaces_exclude; } METHOD(kernel_interface_t, all_interfaces_usable, bool, private_kernel_interface_t *this) { - return this->ifaces_filter == NULL; + return !this->ifaces_filter; } METHOD(kernel_interface_t, get_address_by_ts, status_t, diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index 0ad566068..6fafeb760 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -91,6 +91,8 @@ struct kernel_ipsec_add_sa_t { uint16_t cpi; /** TRUE to enable UDP encapsulation for NAT traversal */ bool encap; + /** TRUE to enable hardware offloading if available */ + bool hw_offload; /** TRUE to use Extended Sequence Numbers */ bool esn; /** TRUE if initiator of the exchange creating the SA */ diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index 1bf93ad40..8fb48281f 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -321,18 +321,16 @@ static bool cookie_required(private_receiver_t *this, */ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message) { - u_int half_open, half_open_r; + u_int half_open; uint32_t now; now = time_monotonic(NULL); half_open = charon->ike_sa_manager->get_half_open_count( - charon->ike_sa_manager, NULL, FALSE); - half_open_r = charon->ike_sa_manager->get_half_open_count( charon->ike_sa_manager, NULL, TRUE); /* check for cookies in IKEv2 */ if (message->get_major_version(message) == IKEV2_MAJOR_VERSION && - cookie_required(this, half_open_r, now) && !check_cookie(this, message)) + cookie_required(this, half_open, now) && !check_cookie(this, message)) { chunk_t cookie; diff --git a/src/libcharon/plugins/addrblock/Makefile.in b/src/libcharon/plugins/addrblock/Makefile.in index f5dfc14d7..60fd19bdc 100644 --- a/src/libcharon/plugins/addrblock/Makefile.in +++ b/src/libcharon/plugins/addrblock/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/addrblock/addrblock_validator.c b/src/libcharon/plugins/addrblock/addrblock_validator.c index d16a1170c..78e377c2a 100644 --- a/src/libcharon/plugins/addrblock/addrblock_validator.c +++ b/src/libcharon/plugins/addrblock/addrblock_validator.c @@ -56,12 +56,12 @@ static bool check_addrblock(private_addrblock_validator_t *this, } if (!subject_const) { - DBG1(DBG_CFG, "subject certficate lacks ipAddrBlocks extension"); + DBG1(DBG_CFG, "subject certificate lacks ipAddrBlocks extension"); return !this->strict; } if (!issuer_const) { - DBG1(DBG_CFG, "issuer certficate lacks ipAddrBlocks extension"); + DBG1(DBG_CFG, "issuer certificate lacks ipAddrBlocks extension"); return FALSE; } subject_enumerator = subject->create_ipAddrBlock_enumerator(subject); diff --git a/src/libcharon/plugins/android_dns/Makefile.in b/src/libcharon/plugins/android_dns/Makefile.in index d79c753f0..0533d81eb 100644 --- a/src/libcharon/plugins/android_dns/Makefile.in +++ b/src/libcharon/plugins/android_dns/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/android_dns/android_dns_handler.c b/src/libcharon/plugins/android_dns/android_dns_handler.c index 160a145d3..68bbaecb2 100644 --- a/src/libcharon/plugins/android_dns/android_dns_handler.c +++ b/src/libcharon/plugins/android_dns/android_dns_handler.c @@ -182,12 +182,15 @@ METHOD(attribute_handler_t, release, void, } METHOD(enumerator_t, enumerate_dns, bool, - enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data) + enumerator_t *this, va_list args) { + configuration_attribute_type_t *type; + chunk_t *data; + + VA_ARGS_VGET(args, type, data); *type = INTERNAL_IP4_DNS; *data = chunk_empty; - /* stop enumeration */ - this->enumerate = (void*)return_false; + this->venumerate = return_false; return TRUE; } @@ -198,7 +201,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, enumerator_t *enumerator; INIT(enumerator, - .enumerate = (void*)_enumerate_dns, + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate_dns, .destroy = (void*)free, ); return enumerator; diff --git a/src/libcharon/plugins/android_log/Makefile.am b/src/libcharon/plugins/android_log/Makefile.am index 9f82f6e60..4f062ee65 100644 --- a/src/libcharon/plugins/android_log/Makefile.am +++ b/src/libcharon/plugins/android_log/Makefile.am @@ -16,3 +16,4 @@ libstrongswan_android_log_la_SOURCES = \ android_log_logger.c android_log_logger.h libstrongswan_android_log_la_LDFLAGS = -module -avoid-version +libstrongswan_android_log_la_LIBADD = -llog diff --git a/src/libcharon/plugins/android_log/Makefile.in b/src/libcharon/plugins/android_log/Makefile.in index 65cdcff94..bc402ef69 100644 --- a/src/libcharon/plugins/android_log/Makefile.in +++ b/src/libcharon/plugins/android_log/Makefile.in @@ -136,7 +136,7 @@ am__uninstall_files_from_dir = { \ } am__installdirs = "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) -libstrongswan_android_log_la_LIBADD = +libstrongswan_android_log_la_DEPENDENCIES = am_libstrongswan_android_log_la_OBJECTS = android_log_plugin.lo \ android_log_logger.lo libstrongswan_android_log_la_OBJECTS = \ @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ @@ -458,6 +460,7 @@ libstrongswan_android_log_la_SOURCES = \ android_log_logger.c android_log_logger.h libstrongswan_android_log_la_LDFLAGS = -module -avoid-version +libstrongswan_android_log_la_LIBADD = -llog all: all-am .SUFFIXES: diff --git a/src/libcharon/plugins/attr/Makefile.in b/src/libcharon/plugins/attr/Makefile.in index 217a42ae6..9fe4d946f 100644 --- a/src/libcharon/plugins/attr/Makefile.in +++ b/src/libcharon/plugins/attr/Makefile.in @@ -355,6 +355,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/attr/attr_provider.c b/src/libcharon/plugins/attr/attr_provider.c index f4c143641..3310f79fd 100644 --- a/src/libcharon/plugins/attr/attr_provider.c +++ b/src/libcharon/plugins/attr/attr_provider.c @@ -75,17 +75,23 @@ typedef struct { ike_version_t ike; } enumerator_data_t; -/** - * convert enumerator value from attribute_entry - */ -static bool attr_enum_filter(enumerator_data_t *data, attribute_entry_t **in, - configuration_attribute_type_t *type, void* none, chunk_t *value) +CALLBACK(attr_enum_filter, bool, + enumerator_data_t *data, enumerator_t *orig, va_list args) { - if ((*in)->ike == IKE_ANY || (*in)->ike == data->ike) + configuration_attribute_type_t *type; + attribute_entry_t *entry; + chunk_t *value; + + VA_ARGS_VGET(args, type, value); + + while (orig->enumerate(orig, &entry)) { - *type = (*in)->type; - *value = (*in)->value; - return TRUE; + if (entry->ike == IKE_ANY || entry->ike == data->ike) + { + *type = entry->type; + *value = entry->value; + return TRUE; + } } return FALSE; } @@ -112,7 +118,7 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, this->lock->read_lock(this->lock); return enumerator_create_filter( this->attributes->create_enumerator(this->attributes), - (void*)attr_enum_filter, data, attr_enum_destroy); + attr_enum_filter, data, attr_enum_destroy); } return enumerator_create_empty(); } diff --git a/src/libcharon/plugins/attr_sql/Makefile.in b/src/libcharon/plugins/attr_sql/Makefile.in index 668e23f07..b3ddf69b5 100644 --- a/src/libcharon/plugins/attr_sql/Makefile.in +++ b/src/libcharon/plugins/attr_sql/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/attr_sql/attr_sql_provider.c b/src/libcharon/plugins/attr_sql/attr_sql_provider.c index c2410705d..33d9f99fc 100644 --- a/src/libcharon/plugins/attr_sql/attr_sql_provider.c +++ b/src/libcharon/plugins/attr_sql/attr_sql_provider.c @@ -200,7 +200,6 @@ static host_t* get_lease(private_attr_sql_provider_t *this, char *name, "SELECT id, address FROM addresses " "WHERE pool = ? AND identity = 0 LIMIT 1", DB_UINT, pool, DB_UINT, DB_BLOB); - } if (!e || !e->enumerate(e, &id, &address)) @@ -447,7 +446,6 @@ METHOD(attr_sql_provider_t, destroy, void, attr_sql_provider_t *attr_sql_provider_create(database_t *db) { private_attr_sql_provider_t *this; - time_t now = time(NULL); INIT(this, .public = { @@ -460,19 +458,25 @@ attr_sql_provider_t *attr_sql_provider_create(database_t *db) }, .db = db, .history = lib->settings->get_bool(lib->settings, - "%s.plugins.attr-sql.lease_history", TRUE, lib->ns), + "%s.plugins.attr-sql.lease_history", TRUE, lib->ns), ); - /* close any "online" leases in the case we crashed */ - if (this->history) + if (lib->settings->get_bool(lib->settings, + "%s.plugins.attr-sql.crash_recovery", TRUE, lib->ns)) { - this->db->execute(this->db, NULL, + time_t now = time(NULL); + + /* close any "online" leases in the case we crashed */ + if (this->history) + { + this->db->execute(this->db, NULL, "INSERT INTO leases (address, identity, acquired, released)" " SELECT id, identity, acquired, ? FROM addresses " " WHERE released = 0", DB_UINT, now); - } - this->db->execute(this->db, NULL, + } + this->db->execute(this->db, NULL, "UPDATE addresses SET released = ? WHERE released = 0", DB_UINT, now); + } return &this->public; } diff --git a/src/libcharon/plugins/bypass_lan/Makefile.in b/src/libcharon/plugins/bypass_lan/Makefile.in index 9f1dc71c9..6c079481b 100644 --- a/src/libcharon/plugins/bypass_lan/Makefile.in +++ b/src/libcharon/plugins/bypass_lan/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c index e690028f2..644cff029 100644 --- a/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c +++ b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c @@ -110,15 +110,12 @@ static bool policy_equals(bypass_policy_t *a, bypass_policy_t *b) */ static bool consider_interface(private_bypass_lan_listener_t *this, char *iface) { - status_t expected; - if (!iface || !this->ifaces_filter) { return TRUE; } - expected = this->ifaces_exclude ? NOT_FOUND : SUCCESS; - return this->ifaces_filter->find_first(this->ifaces_filter, (void*)streq, - NULL, iface) == expected; + return this->ifaces_filter->find_first(this->ifaces_filter, + linked_list_match_str, NULL, iface) != this->ifaces_exclude; } /** diff --git a/src/libcharon/plugins/certexpire/Makefile.in b/src/libcharon/plugins/certexpire/Makefile.in index ffde2d7aa..acbd7a858 100644 --- a/src/libcharon/plugins/certexpire/Makefile.in +++ b/src/libcharon/plugins/certexpire/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/connmark/Makefile.in b/src/libcharon/plugins/connmark/Makefile.in index 140f1b6ad..55bc25a9f 100644 --- a/src/libcharon/plugins/connmark/Makefile.in +++ b/src/libcharon/plugins/connmark/Makefile.in @@ -359,6 +359,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/coupling/Makefile.in b/src/libcharon/plugins/coupling/Makefile.in index 3910e4ea4..6d6fe25bb 100644 --- a/src/libcharon/plugins/coupling/Makefile.in +++ b/src/libcharon/plugins/coupling/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/dhcp/Makefile.in b/src/libcharon/plugins/dhcp/Makefile.in index 6033c6e12..d3f4ec8bc 100644 --- a/src/libcharon/plugins/dhcp/Makefile.in +++ b/src/libcharon/plugins/dhcp/Makefile.in @@ -356,6 +356,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/dhcp/dhcp_provider.c b/src/libcharon/plugins/dhcp/dhcp_provider.c index f0681b1da..50ffbab9d 100644 --- a/src/libcharon/plugins/dhcp/dhcp_provider.c +++ b/src/libcharon/plugins/dhcp/dhcp_provider.c @@ -151,8 +151,7 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, identification_t *id; host_t *vip; - if (pools->find_first(pools, (linked_list_match_t)streq, - NULL, "dhcp") != SUCCESS) + if (!pools->find_first(pools, linked_list_match_str, NULL, "dhcp")) { return NULL; } diff --git a/src/libcharon/plugins/dhcp/dhcp_socket.c b/src/libcharon/plugins/dhcp/dhcp_socket.c index 807c68274..42f8f1ef9 100644 --- a/src/libcharon/plugins/dhcp/dhcp_socket.c +++ b/src/libcharon/plugins/dhcp/dhcp_socket.c @@ -382,8 +382,7 @@ METHOD(dhcp_socket_t, enroll, dhcp_transaction_t*, while (try <= DHCP_TRIES && discover(this, transaction)) { if (!this->condvar->timed_wait(this->condvar, this->mutex, 1000 * try) && - this->request->find_first(this->request, NULL, - (void**)&transaction) == SUCCESS) + this->request->find_first(this->request, NULL, (void**)&transaction)) { break; } diff --git a/src/libcharon/plugins/dhcp/dhcp_transaction.c b/src/libcharon/plugins/dhcp/dhcp_transaction.c index 3ee88a698..87711799c 100644 --- a/src/libcharon/plugins/dhcp/dhcp_transaction.c +++ b/src/libcharon/plugins/dhcp/dhcp_transaction.c @@ -114,16 +114,22 @@ METHOD(dhcp_transaction_t, add_attribute, void, this->attributes->insert_last(this->attributes, entry); } -/** - * Filter function to map entries to type/data - */ -static bool attribute_filter(void *null, attribute_entry_t **entry, - configuration_attribute_type_t *type, - void **dummy, chunk_t *data) +CALLBACK(attribute_filter, bool, + void *null, enumerator_t *orig, va_list args) { - *type = (*entry)->type; - *data = (*entry)->data; - return TRUE; + configuration_attribute_type_t *type; + attribute_entry_t *entry; + chunk_t *data; + + VA_ARGS_VGET(args, type, data); + + if (orig->enumerate(orig, &entry)) + { + *type = entry->type; + *data = entry->data; + return TRUE; + } + return FALSE; } METHOD(dhcp_transaction_t, create_attribute_enumerator, enumerator_t*, @@ -131,7 +137,7 @@ METHOD(dhcp_transaction_t, create_attribute_enumerator, enumerator_t*, { return enumerator_create_filter( this->attributes->create_enumerator(this->attributes), - (void*)attribute_filter, NULL, NULL); + attribute_filter, NULL, NULL); } /** diff --git a/src/libcharon/plugins/dnscert/Makefile.in b/src/libcharon/plugins/dnscert/Makefile.in index cd66af8c8..3687f0cb7 100644 --- a/src/libcharon/plugins/dnscert/Makefile.in +++ b/src/libcharon/plugins/dnscert/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/dnscert/dnscert_cred.c b/src/libcharon/plugins/dnscert/dnscert_cred.c index d32794c99..533bd5be4 100644 --- a/src/libcharon/plugins/dnscert/dnscert_cred.c +++ b/src/libcharon/plugins/dnscert/dnscert_cred.c @@ -75,12 +75,15 @@ typedef struct { } cert_enumerator_t; METHOD(enumerator_t, cert_enumerator_enumerate, bool, - cert_enumerator_t *this, certificate_t **cert) + cert_enumerator_t *this, va_list args) { + certificate_t **cert; dnscert_t *cur_crt; rr_t *cur_rr; chunk_t certificate; + VA_ARGS_VGET(args, cert); + /* Get the next supported CERT using the inner enumerator. */ while (this->inner->enumerate(this->inner, &cur_rr)) { @@ -175,7 +178,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_cert_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _cert_enumerator_enumerate, .destroy = _cert_enumerator_destroy, }, .inner = response->get_rr_set(response)->create_rr_enumerator( diff --git a/src/libcharon/plugins/duplicheck/Makefile.in b/src/libcharon/plugins/duplicheck/Makefile.in index e4b60e6ad..69959d30f 100644 --- a/src/libcharon/plugins/duplicheck/Makefile.in +++ b/src/libcharon/plugins/duplicheck/Makefile.in @@ -365,6 +365,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -387,6 +388,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_aka/Makefile.in b/src/libcharon/plugins/eap_aka/Makefile.in index 20c0ddb8f..5fff12890 100644 --- a/src/libcharon/plugins/eap_aka/Makefile.in +++ b/src/libcharon/plugins/eap_aka/Makefile.in @@ -359,6 +359,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in index f4fb8ec42..478225562 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in +++ b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in @@ -360,6 +360,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_dynamic/Makefile.in b/src/libcharon/plugins/eap_dynamic/Makefile.in index 2dbc05f02..2591dee55 100644 --- a/src/libcharon/plugins/eap_dynamic/Makefile.in +++ b/src/libcharon/plugins/eap_dynamic/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c index 83ccd3a8a..204fb317d 100644 --- a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c @@ -69,6 +69,15 @@ static bool entry_matches(eap_vendor_type_t *item, eap_vendor_type_t *other) return item->type == other->type && item->vendor == other->vendor; } +CALLBACK(entry_matches_cb, bool, + eap_vendor_type_t *item, va_list args) +{ + eap_vendor_type_t *other; + + VA_ARGS_VGET(args, other); + return entry_matches(item, other); +} + /** * Load the given EAP method */ @@ -121,8 +130,7 @@ static void select_method(private_eap_dynamic_t *this) { if (inner) { - if (inner->find_first(inner, (void*)entry_matches, - NULL, entry) != SUCCESS) + if (!inner->find_first(inner, entry_matches_cb, NULL, entry)) { if (entry->vendor) { diff --git a/src/libcharon/plugins/eap_gtc/Makefile.in b/src/libcharon/plugins/eap_gtc/Makefile.in index 01d509ebd..08d8ef8f6 100644 --- a/src/libcharon/plugins/eap_gtc/Makefile.in +++ b/src/libcharon/plugins/eap_gtc/Makefile.in @@ -357,6 +357,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_identity/Makefile.in b/src/libcharon/plugins/eap_identity/Makefile.in index cc1f21eed..4859833ba 100644 --- a/src/libcharon/plugins/eap_identity/Makefile.in +++ b/src/libcharon/plugins/eap_identity/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_md5/Makefile.in b/src/libcharon/plugins/eap_md5/Makefile.in index 939bbf942..796d42f14 100644 --- a/src/libcharon/plugins/eap_md5/Makefile.in +++ b/src/libcharon/plugins/eap_md5/Makefile.in @@ -357,6 +357,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_mschapv2/Makefile.in b/src/libcharon/plugins/eap_mschapv2/Makefile.in index 1e1936c45..00a9f73da 100644 --- a/src/libcharon/plugins/eap_mschapv2/Makefile.in +++ b/src/libcharon/plugins/eap_mschapv2/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_peap/Makefile.in b/src/libcharon/plugins/eap_peap/Makefile.in index b83a80f73..df3c2eae2 100644 --- a/src/libcharon/plugins/eap_peap/Makefile.in +++ b/src/libcharon/plugins/eap_peap/Makefile.in @@ -359,6 +359,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_radius/Makefile.in b/src/libcharon/plugins/eap_radius/Makefile.in index 29a2f3898..d8ebeb8b5 100644 --- a/src/libcharon/plugins/eap_radius/Makefile.in +++ b/src/libcharon/plugins/eap_radius/Makefile.in @@ -360,6 +360,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_radius/eap_radius_provider.c b/src/libcharon/plugins/eap_radius/eap_radius_provider.c index 9a87ad38d..58bbc2edd 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_provider.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_provider.c @@ -404,11 +404,13 @@ typedef struct { attr_t *current; } attribute_enumerator_t; - METHOD(enumerator_t, attribute_enumerate, bool, - attribute_enumerator_t *this, configuration_attribute_type_t *type, - chunk_t *data) + attribute_enumerator_t *this, va_list args) { + configuration_attribute_type_t *type; + chunk_t *data; + + VA_ARGS_VGET(args, type, data); if (this->current) { destroy_attr(this->current); @@ -446,7 +448,8 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_attribute_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _attribute_enumerate, .destroy = _attribute_destroy, }, .list = linked_list_create(), diff --git a/src/libcharon/plugins/eap_sim/Makefile.in b/src/libcharon/plugins/eap_sim/Makefile.in index b4abce9b3..6c2584ae4 100644 --- a/src/libcharon/plugins/eap_sim/Makefile.in +++ b/src/libcharon/plugins/eap_sim/Makefile.in @@ -359,6 +359,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_sim_file/Makefile.in b/src/libcharon/plugins/eap_sim_file/Makefile.in index 914c8c0be..b2473725a 100644 --- a/src/libcharon/plugins/eap_sim_file/Makefile.in +++ b/src/libcharon/plugins/eap_sim_file/Makefile.in @@ -360,6 +360,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_sim_file/eap_sim_file_triplets.c b/src/libcharon/plugins/eap_sim_file/eap_sim_file_triplets.c index ec1686910..03a60cfb1 100644 --- a/src/libcharon/plugins/eap_sim_file/eap_sim_file_triplets.c +++ b/src/libcharon/plugins/eap_sim_file/eap_sim_file_triplets.c @@ -79,10 +79,8 @@ typedef struct { private_eap_sim_file_triplets_t *this; } triplet_enumerator_t; -/** - * destroy a triplet enumerator - */ -static void enumerator_destroy(triplet_enumerator_t *e) +METHOD(enumerator_t, enumerator_destroy, void, + triplet_enumerator_t *e) { if (e->current) { @@ -97,13 +95,14 @@ static void enumerator_destroy(triplet_enumerator_t *e) free(e); } -/** - * enumerate through triplets - */ -static bool enumerator_enumerate(triplet_enumerator_t *e, identification_t **imsi, - char **rand, char **sres, char **kc) +METHOD(enumerator_t, enumerator_enumerate, bool, + triplet_enumerator_t *e, va_list args) { + identification_t **imsi; triplet_t *triplet; + char **rand, **sres, **kc; + + VA_ARGS_VGET(args, imsi, rand, sres, kc); if (e->inner->enumerate(e->inner, &triplet)) { @@ -121,15 +120,18 @@ static bool enumerator_enumerate(triplet_enumerator_t *e, identification_t **ims METHOD(eap_sim_file_triplets_t, create_enumerator, enumerator_t*, private_eap_sim_file_triplets_t *this) { - triplet_enumerator_t *enumerator = malloc_thing(triplet_enumerator_t); + triplet_enumerator_t *enumerator; this->mutex->lock(this->mutex); - enumerator->public.enumerate = (void*)enumerator_enumerate; - enumerator->public.destroy = (void*)enumerator_destroy; - enumerator->inner = this->triplets->create_enumerator(this->triplets); - enumerator->current = NULL; - enumerator->this = this; - + INIT(enumerator, + .public = { + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerator_enumerate, + .destroy = _enumerator_destroy, + }, + .inner = this->triplets->create_enumerator(this->triplets), + .this = this, + ); return &enumerator->public; } diff --git a/src/libcharon/plugins/eap_sim_pcsc/Makefile.in b/src/libcharon/plugins/eap_sim_pcsc/Makefile.in index 48ef92136..88c31a95e 100644 --- a/src/libcharon/plugins/eap_sim_pcsc/Makefile.in +++ b/src/libcharon/plugins/eap_sim_pcsc/Makefile.in @@ -361,6 +361,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in index 5f12e2e2e..62c8ca11e 100644 --- a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in @@ -361,6 +361,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in index 45e2b7498..ef20102bb 100644 --- a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in @@ -360,6 +360,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_simaka_sql/Makefile.in b/src/libcharon/plugins/eap_simaka_sql/Makefile.in index 8c134cff9..c9af52fa9 100644 --- a/src/libcharon/plugins/eap_simaka_sql/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_sql/Makefile.in @@ -359,6 +359,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c index 90627b52e..0f59c5b78 100644 --- a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c +++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c @@ -2,6 +2,9 @@ * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * + * Copyright (C) 2017 Andreas Steffen + * HSR 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 @@ -54,7 +57,7 @@ METHOD(simaka_card_t, get_triplet, bool, snprintf(buf, sizeof(buf), "%Y", id); query = this->db->query(this->db, "select sres, kc from triplets where rand = ? and id = ? " - "order by use limit 1", + "order by used limit 1", DB_BLOB, chunk_create(rand, SIM_RAND_LEN), DB_TEXT, buf, DB_BLOB, DB_BLOB); if (query) @@ -82,7 +85,7 @@ METHOD(simaka_card_t, get_triplet, bool, else { this->db->execute(this->db, NULL, - "update triplets set use = ? where id = ? and rand = ?", + "update triplets set used = ? where id = ? and rand = ?", DB_UINT, time(NULL), DB_TEXT, buf, DB_BLOB, chunk_create(rand, SIM_RAND_LEN)); } @@ -102,7 +105,7 @@ METHOD(simaka_card_t, get_quintuplet, status_t, snprintf(buf, sizeof(buf), "%Y", id); query = this->db->query(this->db, "select ck, ik, res from quintuplets " - "where rand = ? and autn = ? and id = ? order by use limit 1", + "where rand = ? and autn = ? and id = ? order by used limit 1", DB_BLOB, chunk_create(rand, AKA_RAND_LEN), DB_BLOB, chunk_create(autn, AKA_AUTN_LEN), DB_TEXT, buf, DB_BLOB, DB_BLOB, DB_BLOB); @@ -134,7 +137,7 @@ METHOD(simaka_card_t, get_quintuplet, status_t, else { this->db->execute(this->db, NULL, - "update quintuplets set use = ? where id = ? and rand = ?", + "update quintuplets set used = ? where id = ? and rand = ?", DB_UINT, time(NULL), DB_TEXT, buf, DB_BLOB, chunk_create(rand, AKA_RAND_LEN)); } diff --git a/src/libcharon/plugins/eap_tls/Makefile.in b/src/libcharon/plugins/eap_tls/Makefile.in index a9a2dede9..dfe6d8b03 100644 --- a/src/libcharon/plugins/eap_tls/Makefile.in +++ b/src/libcharon/plugins/eap_tls/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_tnc/Makefile.in b/src/libcharon/plugins/eap_tnc/Makefile.in index cda1728c0..902d79d76 100644 --- a/src/libcharon/plugins/eap_tnc/Makefile.in +++ b/src/libcharon/plugins/eap_tnc/Makefile.in @@ -359,6 +359,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/eap_ttls/Makefile.in b/src/libcharon/plugins/eap_ttls/Makefile.in index a72b00576..53fb187fd 100644 --- a/src/libcharon/plugins/eap_ttls/Makefile.in +++ b/src/libcharon/plugins/eap_ttls/Makefile.in @@ -360,6 +360,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/error_notify/Makefile.in b/src/libcharon/plugins/error_notify/Makefile.in index 33862f01a..1514f4011 100644 --- a/src/libcharon/plugins/error_notify/Makefile.in +++ b/src/libcharon/plugins/error_notify/Makefile.in @@ -366,6 +366,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -388,6 +389,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/ext_auth/Makefile.in b/src/libcharon/plugins/ext_auth/Makefile.in index de83d83d5..c3a18191f 100644 --- a/src/libcharon/plugins/ext_auth/Makefile.in +++ b/src/libcharon/plugins/ext_auth/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/farp/Makefile.in b/src/libcharon/plugins/farp/Makefile.in index daee657e7..3de99da38 100644 --- a/src/libcharon/plugins/farp/Makefile.in +++ b/src/libcharon/plugins/farp/Makefile.in @@ -356,6 +356,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/forecast/Makefile.in b/src/libcharon/plugins/forecast/Makefile.in index 5254bca04..5263ccd43 100644 --- a/src/libcharon/plugins/forecast/Makefile.in +++ b/src/libcharon/plugins/forecast/Makefile.in @@ -359,6 +359,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/forecast/forecast_listener.c b/src/libcharon/plugins/forecast/forecast_listener.c index 2024c2682..4585731de 100644 --- a/src/libcharon/plugins/forecast/forecast_listener.c +++ b/src/libcharon/plugins/forecast/forecast_listener.c @@ -613,17 +613,23 @@ METHOD(listener_t, ike_update, bool, return TRUE; } -/** - * Filter to map entries to ts/mark - */ -static bool ts_filter(entry_t *entry, traffic_selector_t **ts, - traffic_selector_t **out, void *dummy, uint32_t *mark, - void *dummy2, bool *reinject) +CALLBACK(ts_filter, bool, + entry_t *entry, enumerator_t *orig, va_list args) { - *out = *ts; - *mark = entry->mark; - *reinject = entry->reinject; - return TRUE; + traffic_selector_t *ts, **out; + uint32_t *mark; + bool *reinject; + + VA_ARGS_VGET(args, out, mark, reinject); + + if (orig->enumerate(orig, &ts)) + { + *out = ts; + *mark = entry->mark; + *reinject = entry->reinject; + return TRUE; + } + return FALSE; } /** @@ -632,7 +638,7 @@ static bool ts_filter(entry_t *entry, traffic_selector_t **ts, static enumerator_t* create_inner_local(entry_t *entry, rwlock_t *lock) { return enumerator_create_filter(array_create_enumerator(entry->lts), - (void*)ts_filter, entry, NULL); + ts_filter, entry, NULL); } /** @@ -641,7 +647,7 @@ static enumerator_t* create_inner_local(entry_t *entry, rwlock_t *lock) static enumerator_t* create_inner_remote(entry_t *entry, rwlock_t *lock) { return enumerator_create_filter(array_create_enumerator(entry->rts), - (void*)ts_filter, entry, NULL); + ts_filter, entry, NULL); } METHOD(forecast_listener_t, create_enumerator, enumerator_t*, diff --git a/src/libcharon/plugins/ha/Makefile.in b/src/libcharon/plugins/ha/Makefile.in index dd2a7a94c..d82bdd28e 100644 --- a/src/libcharon/plugins/ha/Makefile.in +++ b/src/libcharon/plugins/ha/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index ee66b8442..7d22257c6 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -818,14 +818,14 @@ static void process_child_add(private_ha_dispatcher_t *this, } enumerator->destroy(enumerator); + child_sa->set_policies(child_sa, local_ts, remote_ts); + if (initiator) { if (child_sa->install(child_sa, encr_r, integ_r, inbound_spi, - inbound_cpi, initiator, TRUE, TRUE, - local_ts, remote_ts) != SUCCESS || + inbound_cpi, initiator, TRUE, TRUE) != SUCCESS || child_sa->install(child_sa, encr_i, integ_i, outbound_spi, - outbound_cpi, initiator, FALSE, TRUE, - local_ts, remote_ts) != SUCCESS) + outbound_cpi, initiator, FALSE, TRUE) != SUCCESS) { failed = TRUE; } @@ -833,11 +833,9 @@ static void process_child_add(private_ha_dispatcher_t *this, else { if (child_sa->install(child_sa, encr_i, integ_i, inbound_spi, - inbound_cpi, initiator, TRUE, TRUE, - local_ts, remote_ts) != SUCCESS || + inbound_cpi, initiator, TRUE, TRUE) != SUCCESS || child_sa->install(child_sa, encr_r, integ_r, outbound_spi, - outbound_cpi, initiator, FALSE, TRUE, - local_ts, remote_ts) != SUCCESS) + outbound_cpi, initiator, FALSE, TRUE) != SUCCESS) { failed = TRUE; } @@ -868,7 +866,7 @@ static void process_child_add(private_ha_dispatcher_t *this, child_sa->get_unique_id(child_sa), local_ts, remote_ts, seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "", seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : ""); - child_sa->add_policies(child_sa, local_ts, remote_ts); + child_sa->install_policies(child_sa); local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy)); remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy)); diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c index 42dfaf0e2..5f73b7156 100644 --- a/src/libcharon/plugins/ha/ha_message.c +++ b/src/libcharon/plugins/ha/ha_message.c @@ -331,10 +331,12 @@ typedef struct { } attribute_enumerator_t; METHOD(enumerator_t, attribute_enumerate, bool, - attribute_enumerator_t *this, ha_message_attribute_t *attr_out, - ha_message_value_t *value) + attribute_enumerator_t *this, va_list args) { - ha_message_attribute_t attr; + ha_message_attribute_t attr, *attr_out; + ha_message_value_t *value; + + VA_ARGS_VGET(args, attr_out, value); if (this->cleanup) { @@ -602,7 +604,8 @@ METHOD(ha_message_t, create_attribute_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_attribute_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _attribute_enumerate, .destroy = _enum_destroy, }, .buf = chunk_skip(this->buf, 2), diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index a0e514614..1a6108ed9 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -111,8 +111,12 @@ typedef struct { } shared_enum_t; METHOD(enumerator_t, shared_enumerate, bool, - shared_enum_t *this, shared_key_t **key, id_match_t *me, id_match_t *other) + shared_enum_t *this, va_list args) { + shared_key_t **key; + id_match_t *me, *other; + + VA_ARGS_VGET(args, key, me, other); if (this->key) { if (me) @@ -151,7 +155,8 @@ METHOD(ha_creds_t, create_shared_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_shared_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _shared_enumerate, .destroy = (void*)free, }, .key = this->key, diff --git a/src/libcharon/plugins/ipseckey/Makefile.in b/src/libcharon/plugins/ipseckey/Makefile.in index 025a1a25e..02243e47c 100644 --- a/src/libcharon/plugins/ipseckey/Makefile.in +++ b/src/libcharon/plugins/ipseckey/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/ipseckey/ipseckey_cred.c b/src/libcharon/plugins/ipseckey/ipseckey_cred.c index ff50d8a17..b3ac2b328 100644 --- a/src/libcharon/plugins/ipseckey/ipseckey_cred.c +++ b/src/libcharon/plugins/ipseckey/ipseckey_cred.c @@ -62,13 +62,16 @@ typedef struct { } cert_enumerator_t; METHOD(enumerator_t, cert_enumerator_enumerate, bool, - cert_enumerator_t *this, certificate_t **cert) + cert_enumerator_t *this, va_list args) { + certificate_t **cert; ipseckey_t *cur_ipseckey; public_key_t *public; rr_t *cur_rr; chunk_t key; + VA_ARGS_VGET(args, cert); + /* Get the next supported IPSECKEY using the inner enumerator. */ while (this->inner->enumerate(this->inner, &cur_rr)) { @@ -211,7 +214,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_cert_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _cert_enumerator_enumerate, .destroy = _cert_enumerator_destroy, }, .inner = rrset->create_rr_enumerator(rrset), diff --git a/src/libcharon/plugins/kernel_iph/Makefile.in b/src/libcharon/plugins/kernel_iph/Makefile.in index fb8e42ee6..d9c172c1d 100644 --- a/src/libcharon/plugins/kernel_iph/Makefile.in +++ b/src/libcharon/plugins/kernel_iph/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c index efeb98045..18a87b707 100644 --- a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c +++ b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c @@ -466,9 +466,12 @@ typedef struct { } addr_enumerator_t; METHOD(enumerator_t, addr_enumerate, bool, - addr_enumerator_t *this, host_t **host) + addr_enumerator_t *this, va_list args) { iface_t *entry; + host_t **host; + + VA_ARGS_VGET(args, host); while (TRUE) { @@ -523,7 +526,8 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_addr_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _addr_enumerate, .destroy = _addr_destroy, }, .which = which, diff --git a/src/libcharon/plugins/kernel_libipsec/Makefile.in b/src/libcharon/plugins/kernel_libipsec/Makefile.in index 4d5e46033..9f1a490cf 100644 --- a/src/libcharon/plugins/kernel_libipsec/Makefile.in +++ b/src/libcharon/plugins/kernel_libipsec/Makefile.in @@ -360,6 +360,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c index 77e37e249..d4832e233 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c @@ -84,12 +84,12 @@ static void exclude_route_destroy(exclude_route_t *this) free(this); } -/** - * Find an exclude route entry by destination address - */ -static bool exclude_route_match(exclude_route_t *current, - host_t *dst) +CALLBACK(exclude_route_match, bool, + exclude_route_t *current, va_list args) { + host_t *dst; + + VA_ARGS_VGET(args, dst); return dst->ip_equals(dst, current->dst); } @@ -204,12 +204,12 @@ static void policy_entry_destroy(policy_entry_t *this) free(this); } -/** - * Compare two policy_entry_t objects - */ -static inline bool policy_entry_equals(policy_entry_t *a, - policy_entry_t *b) +CALLBACK(policy_entry_equals, bool, + policy_entry_t *a, va_list args) { + policy_entry_t *b; + + VA_ARGS_VGET(args, b); return a->direction == b->direction && a->src.proto == b->src.proto && a->dst.proto == b->dst.proto && @@ -297,9 +297,8 @@ static void add_exclude_route(private_kernel_libipsec_ipsec_t *this, exclude_route_t *exclude; host_t *gtw; - if (this->excludes->find_first(this->excludes, - (linked_list_match_t)exclude_route_match, - (void**)&exclude, dst) == SUCCESS) + if (this->excludes->find_first(this->excludes, exclude_route_match, + (void**)&exclude, dst)) { route->exclude = exclude; exclude->refs++; @@ -524,9 +523,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t, policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); this->mutex->lock(this->mutex); - if (this->policies->find_first(this->policies, - (linked_list_match_t)policy_entry_equals, - (void**)&found, policy) == SUCCESS) + if (this->policies->find_first(this->policies, policy_entry_equals, + (void**)&found, policy)) { policy_entry_destroy(policy); policy = found; @@ -567,9 +565,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t, policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); this->mutex->lock(this->mutex); - if (this->policies->find_first(this->policies, - (linked_list_match_t)policy_entry_equals, - (void**)&found, policy) != SUCCESS) + if (!this->policies->find_first(this->policies, policy_entry_equals, + (void**)&found, policy)) { policy_entry_destroy(policy); this->mutex->unlock(this->mutex); diff --git a/src/libcharon/plugins/kernel_netlink/Makefile.in b/src/libcharon/plugins/kernel_netlink/Makefile.in index 26a7090b3..7f25c5202 100644 --- a/src/libcharon/plugins/kernel_netlink/Makefile.in +++ b/src/libcharon/plugins/kernel_netlink/Makefile.in @@ -397,6 +397,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -419,6 +420,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index becf6b5dc..c411b829d 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -78,9 +78,6 @@ /** Base priority for installed policies */ #define PRIO_BASE 200000 -/** Default lifetime of an acquire XFRM state (in seconds) */ -#define DEFAULT_ACQUIRE_LIFETIME 165 - /** * Map the limit for bytes and packets to XFRM_INF by default */ @@ -545,10 +542,10 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this, /** * Destroy a policy_sa(_in)_t object */ -static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir, +static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t dir, private_kernel_netlink_ipsec_t *this) { - if (*dir == POLICY_OUT) + if (dir == POLICY_OUT) { policy_sa_out_t *out = (policy_sa_out_t*)policy; out->src_ts->destroy(out->src_ts); @@ -558,6 +555,16 @@ static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir, free(policy); } +CALLBACK(policy_sa_destroy_cb, void, + policy_sa_t *policy, va_list args) +{ + private_kernel_netlink_ipsec_t *this; + policy_dir_t dir; + + VA_ARGS_VGET(args, dir, this); + policy_sa_destroy(policy, dir, this); +} + typedef struct policy_entry_t policy_entry_t; /** @@ -602,9 +609,8 @@ static void policy_entry_destroy(private_kernel_netlink_ipsec_t *this, } if (policy->used_by) { - policy->used_by->invoke_function(policy->used_by, - (linked_list_invoke_t)policy_sa_destroy, - &policy->direction, this); + policy->used_by->invoke_function(policy->used_by, policy_sa_destroy_cb, + policy->direction, this); policy->used_by->destroy(policy->used_by); } free(policy); @@ -1639,12 +1645,46 @@ METHOD(kernel_ipsec_t, add_sa, status_t, data->replay_window); sa->replay_window = data->replay_window; } + if (data->hw_offload) + { + host_t *local = data->inbound ? id->dst : id->src; + char *ifname; + + if (charon->kernel->get_interface(charon->kernel, local, &ifname)) + { + struct xfrm_user_offload *offload; + + offload = netlink_reserve(hdr, sizeof(request), + XFRMA_OFFLOAD_DEV, sizeof(*offload)); + if (!offload) + { + free(ifname); + goto failed; + } + offload->ifindex = if_nametoindex(ifname); + if (local->get_family(local) == AF_INET6) + { + offload->flags |= XFRM_OFFLOAD_IPV6; + } + offload->flags |= data->inbound ? XFRM_OFFLOAD_INBOUND : 0; + free(ifname); + } + } } - if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) + status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr); + if (status == NOT_FOUND && data->update) { - DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x%s", ntohl(id->spi), - markstr); + DBG1(DBG_KNL, "allocated SPI not found anymore, try to add SAD entry"); + hdr->nlmsg_type = XFRM_MSG_NEWSA; + status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr); + } + + if (status != SUCCESS) + { + DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x%s (%N)", ntohl(id->spi), + markstr, status_names, status); + status = FAILED; goto failed; } @@ -1919,13 +1959,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t, kernel_ipsec_update_sa_t *data) { netlink_buf_t request; - struct nlmsghdr *hdr, *out = NULL; + struct nlmsghdr *hdr, *out_hdr = NULL, *out = NULL; struct xfrm_usersa_id *sa_id; - struct xfrm_usersa_info *out_sa = NULL, *sa; + struct xfrm_usersa_info *sa; size_t len; struct rtattr *rta; size_t rtasize; - struct xfrm_encap_tmpl* tmpl = NULL; + struct xfrm_encap_tmpl* encap = NULL; struct xfrm_replay_state *replay = NULL; struct xfrm_replay_state_esn *replay_esn = NULL; struct xfrm_lifetime_cur *lifetime = NULL; @@ -1983,7 +2023,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { case XFRM_MSG_NEWSA: { - out_sa = NLMSG_DATA(hdr); + out_hdr = hdr; break; } case NLMSG_ERROR: @@ -2002,7 +2042,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, break; } } - if (out_sa == NULL) + if (!out_hdr) { DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x%s", ntohl(id->spi), markstr); @@ -2029,7 +2069,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, hdr->nlmsg_type = XFRM_MSG_NEWSA; hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); sa = NLMSG_DATA(hdr); - memcpy(sa, NLMSG_DATA(out), sizeof(struct xfrm_usersa_info)); + memcpy(sa, NLMSG_DATA(out_hdr), sizeof(struct xfrm_usersa_info)); sa->family = data->new_dst->get_family(data->new_dst); if (!id->src->ip_equals(id->src, data->new_src)) @@ -2041,8 +2081,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t, host2xfrm(data->new_dst, &sa->id.daddr); } - rta = XFRM_RTA(out, struct xfrm_usersa_info); - rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info); + rta = XFRM_RTA(out_hdr, struct xfrm_usersa_info); + rtasize = XFRM_PAYLOAD(out_hdr, struct xfrm_usersa_info); while (RTA_OK(rta, rtasize)) { /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ @@ -2050,9 +2090,34 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { if (rta->rta_type == XFRMA_ENCAP) { /* update encap tmpl */ - tmpl = RTA_DATA(rta); - tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src)); - tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); + encap = RTA_DATA(rta); + encap->encap_sport = ntohs(data->new_src->get_port(data->new_src)); + encap->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); + } + if (rta->rta_type == XFRMA_OFFLOAD_DEV) + { /* update offload device */ + struct xfrm_user_offload *offload; + host_t *local; + char *ifname; + + offload = RTA_DATA(rta); + local = offload->flags & XFRM_OFFLOAD_INBOUND ? data->new_dst + : data->new_src; + + if (charon->kernel->get_interface(charon->kernel, local, + &ifname)) + { + offload->ifindex = if_nametoindex(ifname); + if (local->get_family(local) == AF_INET6) + { + offload->flags |= XFRM_OFFLOAD_IPV6; + } + else + { + offload->flags &= ~XFRM_OFFLOAD_IPV6; + } + free(ifname); + } } netlink_add_attribute(hdr, rta->rta_type, chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)), @@ -2061,17 +2126,18 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta = RTA_NEXT(rta, rtasize); } - if (tmpl == NULL && data->new_encap) + if (encap == NULL && data->new_encap) { /* add tmpl if we are enabling it */ - tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl)); - if (!tmpl) + encap = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, + sizeof(*encap)); + if (!encap) { goto failed; } - tmpl->encap_type = UDP_ENCAP_ESPINUDP; - tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src)); - tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); - memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); + encap->encap_type = UDP_ENCAP_ESPINUDP; + encap->encap_sport = ntohs(data->new_src->get_port(data->new_src)); + encap->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); + memset(&encap->encap_oa, 0, sizeof (xfrm_address_t)); } if (replay_esn) @@ -2711,7 +2777,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, ipsec_sa_equals(mapping->sa, &assigned_sa)) { current->used_by->remove_at(current->used_by, enumerator); - policy_sa_destroy(mapping, &id->dir, this); + policy_sa_destroy(mapping, id->dir, this); break; } if (is_installed) @@ -3171,7 +3237,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() { private_kernel_netlink_ipsec_t *this; bool register_for_events = TRUE; - FILE *f; INIT(this, .public = { @@ -3216,15 +3281,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() register_for_events = FALSE; } - f = fopen("/proc/sys/net/core/xfrm_acq_expires", "w"); - if (f) - { - fprintf(f, "%u", lib->settings->get_int(lib->settings, - "%s.plugins.kernel-netlink.xfrm_acq_expires", - DEFAULT_ACQUIRE_LIFETIME, lib->ns)); - fclose(f); - } - this->socket_xfrm = netlink_socket_create(NETLINK_XFRM, xfrm_msg_names, lib->settings->get_bool(lib->settings, "%s.plugins.kernel-netlink.parallel_xfrm", FALSE, lib->ns)); diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c index 2dc76d941..0dd3e30cb 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c @@ -163,19 +163,21 @@ static void iface_entry_destroy(iface_entry_t *this) free(this); } -/** - * find an interface entry by index - */ -static bool iface_entry_by_index(iface_entry_t *this, int *ifindex) +CALLBACK(iface_entry_by_index, bool, + iface_entry_t *this, va_list args) { - return this->ifindex == *ifindex; + int ifindex; + + VA_ARGS_VGET(args, ifindex); + return this->ifindex == ifindex; } -/** - * find an interface entry by name - */ -static bool iface_entry_by_name(iface_entry_t *this, char *ifname) +CALLBACK(iface_entry_by_name, bool, + iface_entry_t *this, va_list args) { + char *ifname; + + VA_ARGS_VGET(args, ifname); return streq(this->ifname, ifname); } @@ -1112,8 +1114,8 @@ static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this, { iface_entry_t *iface; - if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index, - (void**)&iface, &index) == SUCCESS) + if (this->ifaces->find_first(this->ifaces, iface_entry_by_index, + (void**)&iface, index)) { return iface_entry_up_and_usable(iface); } @@ -1125,9 +1127,13 @@ static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this, * * this->lock must be locked when calling this function */ -static void addr_entry_unregister(addr_entry_t *addr, iface_entry_t *iface, - private_kernel_netlink_net_t *this) +CALLBACK(addr_entry_unregister, void, + addr_entry_t *addr, va_list args) { + private_kernel_netlink_net_t *this; + iface_entry_t *iface; + + VA_ARGS_VGET(args, iface, this); if (addr->refcount) { addr_map_entry_remove(this->vips, addr, iface); @@ -1171,9 +1177,8 @@ static void process_link(private_kernel_netlink_net_t *this, { case RTM_NEWLINK: { - if (this->ifaces->find_first(this->ifaces, - (void*)iface_entry_by_index, (void**)&entry, - &msg->ifi_index) != SUCCESS) + if (!this->ifaces->find_first(this->ifaces, iface_entry_by_index, + (void**)&entry, msg->ifi_index)) { INIT(entry, .ifindex = msg->ifi_index, @@ -1217,7 +1222,7 @@ static void process_link(private_kernel_netlink_net_t *this, * another interface? */ this->ifaces->remove_at(this->ifaces, enumerator); current->addrs->invoke_function(current->addrs, - (void*)addr_entry_unregister, current, this); + addr_entry_unregister, current, this); iface_entry_destroy(current); break; } @@ -1288,8 +1293,8 @@ static void process_addr(private_kernel_netlink_net_t *this, } this->lock->write_lock(this->lock); - if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index, - (void**)&iface, &msg->ifa_index) == SUCCESS) + if (this->ifaces->find_first(this->ifaces, iface_entry_by_index, + (void**)&iface, msg->ifa_index)) { addr_map_entry_t *entry, lookup = { .ip = host, @@ -1518,35 +1523,39 @@ typedef struct { kernel_address_type_t which; } address_enumerator_t; -/** - * cleanup function for address enumerator - */ -static void address_enumerator_destroy(address_enumerator_t *data) +CALLBACK(address_enumerator_destroy, void, + address_enumerator_t *data) { data->this->lock->unlock(data->this->lock); free(data); } -/** - * filter for addresses - */ -static bool filter_addresses(address_enumerator_t *data, - addr_entry_t** in, host_t** out) +CALLBACK(filter_addresses, bool, + address_enumerator_t *data, enumerator_t *orig, va_list args) { - if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->refcount) - { /* skip virtual interfaces added by us */ - return FALSE; - } - if (!(data->which & ADDR_TYPE_REGULAR) && !(*in)->refcount) - { /* address is regular, but not requested */ - return FALSE; - } - if ((*in)->scope >= RT_SCOPE_LINK) - { /* skip addresses with a unusable scope */ - return FALSE; + addr_entry_t *addr; + host_t **out; + + VA_ARGS_VGET(args, out); + + while (orig->enumerate(orig, &addr)) + { + if (!(data->which & ADDR_TYPE_VIRTUAL) && addr->refcount) + { /* skip virtual interfaces added by us */ + continue; + } + if (!(data->which & ADDR_TYPE_REGULAR) && !addr->refcount) + { /* address is regular, but not requested */ + continue; + } + if (addr->scope >= RT_SCOPE_LINK) + { /* skip addresses with a unusable scope */ + continue; + } + *out = addr->ip; + return TRUE; } - *out = (*in)->ip; - return TRUE; + return FALSE; } /** @@ -1556,30 +1565,35 @@ static enumerator_t *create_iface_enumerator(iface_entry_t *iface, address_enumerator_t *data) { return enumerator_create_filter( - iface->addrs->create_enumerator(iface->addrs), - (void*)filter_addresses, data, NULL); + iface->addrs->create_enumerator(iface->addrs), + filter_addresses, data, NULL); } -/** - * filter for interfaces - */ -static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in, - iface_entry_t** out) +CALLBACK(filter_interfaces, bool, + address_enumerator_t *data, enumerator_t *orig, va_list args) { - if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable) - { /* skip interfaces excluded by config */ - return FALSE; - } - if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK)) - { /* ignore loopback devices */ - return FALSE; - } - if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP)) - { /* skip interfaces not up */ - return FALSE; + iface_entry_t *iface, **out; + + VA_ARGS_VGET(args, out); + + while (orig->enumerate(orig, &iface)) + { + if (!(data->which & ADDR_TYPE_IGNORED) && !iface->usable) + { /* skip interfaces excluded by config */ + continue; + } + if (!(data->which & ADDR_TYPE_LOOPBACK) && (iface->flags & IFF_LOOPBACK)) + { /* ignore loopback devices */ + continue; + } + if (!(data->which & ADDR_TYPE_DOWN) && !(iface->flags & IFF_UP)) + { /* skip interfaces not up */ + continue; + } + *out = iface; + return TRUE; } - *out = *in; - return TRUE; + return FALSE; } METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, @@ -1596,9 +1610,9 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, return enumerator_create_nested( enumerator_create_filter( this->ifaces->create_enumerator(this->ifaces), - (void*)filter_interfaces, data, NULL), + filter_interfaces, data, NULL), (void*)create_iface_enumerator, data, - (void*)address_enumerator_destroy); + address_enumerator_destroy); } METHOD(kernel_net_t, get_interface_name, bool, @@ -1661,8 +1675,8 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name) DBG2(DBG_KNL, "getting iface index for %s", name); this->lock->read_lock(this->lock); - if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name, - (void**)&iface, name) == SUCCESS) + if (this->ifaces->find_first(this->ifaces, iface_entry_by_name, + (void**)&iface, name)) { ifindex = iface->ifindex; } @@ -1687,8 +1701,8 @@ static char *get_interface_name_by_index(private_kernel_netlink_net_t *this, DBG2(DBG_KNL, "getting iface name for index %d", index); this->lock->read_lock(this->lock); - if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index, - (void**)&iface, &index) == SUCCESS) + if (this->ifaces->find_first(this->ifaces, iface_entry_by_index, + (void**)&iface, index)) { name = strdup(iface->ifname); } @@ -1928,7 +1942,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, table = (uintptr_t)route->table; if (this->rt_exclude->find_first(this->rt_exclude, NULL, - (void**)&table) == SUCCESS) + (void**)&table)) { /* route is from an excluded routing table */ continue; } @@ -2165,8 +2179,14 @@ METHOD(enumerator_t, destroy_subnet_enumerator, void, } METHOD(enumerator_t, enumerate_subnets, bool, - subnet_enumerator_t *this, host_t **net, uint8_t *mask, char **ifname) + subnet_enumerator_t *this, va_list args) { + host_t **net; + uint8_t *mask; + char **ifname; + + VA_ARGS_VGET(args, net, mask, ifname); + if (!this->current) { this->current = this->msg; @@ -2270,7 +2290,8 @@ METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_enumerate_subnets, + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate_subnets, .destroy = _destroy_subnet_enumerator, }, .private = this, @@ -2380,11 +2401,11 @@ METHOD(kernel_net_t, add_ip, status_t, } /* try to find the target interface, either by config or via src ip */ if (!this->install_virtual_ip_on || - this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name, - (void**)&iface, this->install_virtual_ip_on) != SUCCESS) + !this->ifaces->find_first(this->ifaces, iface_entry_by_name, + (void**)&iface, this->install_virtual_ip_on)) { - if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name, - (void**)&iface, iface_name) != SUCCESS) + if (!this->ifaces->find_first(this->ifaces, iface_entry_by_name, + (void**)&iface, iface_name)) { /* if we don't find the requested interface we just use the first */ this->ifaces->get_first(this->ifaces, (void**)&iface); } diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c index 8bafc3c55..58350028f 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c @@ -19,6 +19,8 @@ #include "kernel_netlink_ipsec.h" #include "kernel_netlink_net.h" +#include <sa/task_manager.h> + typedef struct private_kernel_netlink_plugin_t private_kernel_netlink_plugin_t; /** @@ -50,6 +52,24 @@ METHOD(plugin_t, get_features, int, return countof(f); } +METHOD(plugin_t, reload, bool, + private_kernel_netlink_plugin_t *this) +{ + u_int timeout; + FILE *f; + + f = fopen("/proc/sys/net/core/xfrm_acq_expires", "w"); + if (f) + { + timeout = lib->settings->get_int(lib->settings, + "%s.plugins.kernel-netlink.xfrm_acq_expires", + task_manager_total_retransmit_timeout(), lib->ns); + fprintf(f, "%u", timeout); + fclose(f); + } + return TRUE; +} + METHOD(plugin_t, destroy, void, private_kernel_netlink_plugin_t *this) { @@ -76,10 +96,13 @@ plugin_t *kernel_netlink_plugin_create() .plugin = { .get_name = _get_name, .get_features = _get_features, + .reload = _reload, .destroy = _destroy, }, }, ); + reload(this); + return &this->public.plugin; } diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c index da54031a1..cf85cb0a6 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c @@ -333,7 +333,8 @@ static status_t send_once(private_netlink_socket_t *this, struct nlmsghdr *in, while (!entry->complete) { if (this->parallel && - lib->watcher->get_state(lib->watcher) != WATCHER_STOPPED) + lib->watcher->get_state(lib->watcher) != WATCHER_STOPPED && + lib->processor->get_total_threads(lib->processor)) { if (this->timeout) { diff --git a/src/libcharon/plugins/kernel_pfkey/Makefile.in b/src/libcharon/plugins/kernel_pfkey/Makefile.in index b138a9603..b27408a3f 100644 --- a/src/libcharon/plugins/kernel_pfkey/Makefile.in +++ b/src/libcharon/plugins/kernel_pfkey/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 17878147b..fd1adb2ae 100644 --- a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -464,10 +464,10 @@ static policy_sa_t *policy_sa_create(private_kernel_pfkey_ipsec_t *this, /** * Destroy a policy_sa(_in)_t object */ -static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir, +static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t dir, private_kernel_pfkey_ipsec_t *this) { - if (*dir == POLICY_OUT) + if (dir == POLICY_OUT) { policy_sa_out_t *out = (policy_sa_out_t*)policy; out->src_ts->destroy(out->src_ts); @@ -477,6 +477,16 @@ static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir, free(policy); } +CALLBACK(policy_sa_destroy_cb, void, + policy_sa_t *policy, va_list args) +{ + private_kernel_pfkey_ipsec_t *this; + policy_dir_t dir; + + VA_ARGS_VGET(args, dir, this); + policy_sa_destroy(policy, dir, this); +} + typedef struct policy_entry_t policy_entry_t; /** @@ -557,9 +567,8 @@ static void policy_entry_destroy(policy_entry_t *policy, } if (policy->used_by) { - policy->used_by->invoke_function(policy->used_by, - (linked_list_invoke_t)policy_sa_destroy, - &policy->direction, this); + policy->used_by->invoke_function(policy->used_by, policy_sa_destroy_cb, + policy->direction, this); policy->used_by->destroy(policy->used_by); } DESTROY_IF(policy->src.net); @@ -567,12 +576,21 @@ static void policy_entry_destroy(policy_entry_t *policy, free(policy); } -/** - * compares two policy_entry_t - */ -static inline bool policy_entry_equals(policy_entry_t *current, - policy_entry_t *policy) +CALLBACK(policy_entry_destroy_cb, void, + policy_entry_t *policy, va_list args) { + private_kernel_pfkey_ipsec_t *this; + + VA_ARGS_VGET(args, this); + policy_entry_destroy(policy, this); +} + +CALLBACK(policy_entry_equals, bool, + policy_entry_t *current, va_list args) +{ + policy_entry_t *policy; + + VA_ARGS_VGET(args, policy); return current->direction == policy->direction && current->src.proto == policy->src.proto && current->dst.proto == policy->dst.proto && @@ -582,13 +600,13 @@ static inline bool policy_entry_equals(policy_entry_t *current, current->dst.net->equals(current->dst.net, policy->dst.net); } -/** - * compare the given kernel index with that of a policy - */ -static inline bool policy_entry_match_byindex(policy_entry_t *current, - uint32_t *index) +CALLBACK(policy_entry_match_byindex, bool, + policy_entry_t *current, va_list args) { - return current->index == *index; + uint32_t index; + + VA_ARGS_VGET(args, index); + return current->index == index; } /** @@ -999,24 +1017,6 @@ static void add_addr_ext(struct sadb_msg *msg, host_t *host, uint16_t type, PFKEY_EXT_ADD(msg, addr); } -/** - * adds an empty address extension to the given sadb_msg - */ -static void add_anyaddr_ext(struct sadb_msg *msg, int family, uint8_t type) -{ - socklen_t len = (family == AF_INET) ? sizeof(struct sockaddr_in) : - sizeof(struct sockaddr_in6); - struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg); - addr->sadb_address_exttype = type; - sockaddr_t *saddr = (sockaddr_t*)(addr + 1); - saddr->sa_family = family; -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - saddr->sa_len = len; -#endif - addr->sadb_address_len = PFKEY_LEN(sizeof(*addr) + len); - PFKEY_EXT_ADD(msg, addr); -} - #ifdef HAVE_NATT /** * add udp encap extensions to a sadb_msg @@ -1279,9 +1279,8 @@ static void process_acquire(private_kernel_pfkey_ipsec_t *this, index = response.x_policy->sadb_x_policy_id; this->mutex->lock(this->mutex); - if (this->policies->find_first(this->policies, - (linked_list_match_t)policy_entry_match_byindex, - (void**)&policy, &index) == SUCCESS && + if (this->policies->find_first(this->policies, policy_entry_match_byindex, + (void**)&policy, index) && policy->used_by->get_first(policy->used_by, (void**)&sa) == SUCCESS) { reqid = sa->sa->cfg.reqid; @@ -1854,6 +1853,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, pfkey_msg_t response; size_t len; +#ifndef SADB_X_EXT_NEW_ADDRESS_SRC /* we can't update the SA if any of the ip addresses have changed. * that's because we can't use SADB_UPDATE and by deleting and readding the * SA the sequence numbers would get lost */ @@ -1864,6 +1864,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, "changes are not supported", ntohl(id->spi)); return NOT_SUPPORTED; } +#endif /*SADB_X_EXT_NEW_ADDRESS_SRC*/ /* if IPComp is used, we first update the IPComp SA */ if (data->cpi) @@ -1900,9 +1901,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, sa->sadb_sa_state = SADB_SASTATE_MATURE; PFKEY_EXT_ADD(msg, sa); - /* the kernel wants a SADB_EXT_ADDRESS_SRC to be present even though - * it is not used for anything. */ - add_anyaddr_ext(msg, id->dst->get_family(id->dst), SADB_EXT_ADDRESS_SRC); + add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); if (pfkey_send(this, msg, &out, &len) != SUCCESS) @@ -1944,7 +1943,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg); sa_2->sa.sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa_2)); memcpy(&sa_2->sa, response.sa, sizeof(struct sadb_sa)); - if (data->encap) + if (data->new_encap) { sa_2->sadb_sa_natt_port = data->new_dst->get_port(data->new_dst); sa_2->sa.sadb_sa_flags |= SADB_X_EXT_NATT; @@ -1978,6 +1977,19 @@ METHOD(kernel_ipsec_t, update_sa, status_t, } #endif /*HAVE_NATT*/ +#ifdef SADB_X_EXT_NEW_ADDRESS_SRC + if (!id->src->ip_equals(id->src, data->new_src)) + { + add_addr_ext(msg, data->new_src, SADB_X_EXT_NEW_ADDRESS_SRC, 0, 0, + FALSE); + } + if (!id->dst->ip_equals(id->dst, data->new_dst)) + { + add_addr_ext(msg, data->new_dst, SADB_X_EXT_NEW_ADDRESS_DST, 0, 0, + FALSE); + } +#endif /*SADB_X_EXT_NEW_ADDRESS_SRC*/ + free(out); if (pfkey_send(this, msg, &out, &len) != SUCCESS) @@ -2559,8 +2571,7 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, /* we try to find the policy again and update the kernel index */ this->mutex->lock(this->mutex); - if (this->policies->find_first(this->policies, NULL, - (void**)&policy) != SUCCESS) + if (!this->policies->find_first(this->policies, NULL, (void**)&policy)) { DBG2(DBG_KNL, "unable to update index, the policy is already gone, " "ignoring"); @@ -2611,9 +2622,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t, /* find a matching policy */ this->mutex->lock(this->mutex); - if (this->policies->find_first(this->policies, - (linked_list_match_t)policy_entry_equals, - (void**)&found, policy) == SUCCESS) + if (this->policies->find_first(this->policies, policy_entry_equals, + (void**)&found, policy)) { /* use existing policy */ DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " "refcount", id->src_ts, id->dst_ts, policy_dir_names, id->dir); @@ -2706,9 +2716,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t, /* find a matching policy */ this->mutex->lock(this->mutex); - if (this->policies->find_first(this->policies, - (linked_list_match_t)policy_entry_equals, - (void**)&found, policy) != SUCCESS) + if (!this->policies->find_first(this->policies, policy_entry_equals, + (void**)&found, policy)) { DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found", id->src_ts, id->dst_ts, policy_dir_names, id->dir); @@ -2819,9 +2828,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t, /* find a matching policy */ this->mutex->lock(this->mutex); - if (this->policies->find_first(this->policies, - (linked_list_match_t)policy_entry_equals, - (void**)&found, policy) != SUCCESS) + if (!this->policies->find_first(this->policies, policy_entry_equals, + (void**)&found, policy)) { DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", id->src_ts, id->dst_ts, policy_dir_names, id->dir); @@ -2865,7 +2873,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, if (policy->used_by->get_count(policy->used_by) > 0) { /* policy is used by more SAs, keep in kernel */ DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); - policy_sa_destroy(mapping, &id->dir, this); + policy_sa_destroy(mapping, id->dir, this); if (!is_installed) { /* no need to update as the policy was not installed for this SA */ @@ -2920,7 +2928,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, } this->policies->remove(this->policies, found, NULL); - policy_sa_destroy(mapping, &id->dir, this); + policy_sa_destroy(mapping, id->dir, this); policy_entry_destroy(policy, this); this->mutex->unlock(this->mutex); @@ -3093,8 +3101,7 @@ METHOD(kernel_ipsec_t, destroy, void, lib->watcher->remove(lib->watcher, this->socket_events); close(this->socket_events); } - this->policies->invoke_function(this->policies, - (linked_list_invoke_t)policy_entry_destroy, + this->policies->invoke_function(this->policies, policy_entry_destroy_cb, this); this->policies->destroy(this->policies); this->excludes->destroy(this->excludes); diff --git a/src/libcharon/plugins/kernel_pfroute/Makefile.in b/src/libcharon/plugins/kernel_pfroute/Makefile.in index 1e4b3e207..e7005bbff 100644 --- a/src/libcharon/plugins/kernel_pfroute/Makefile.in +++ b/src/libcharon/plugins/kernel_pfroute/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c index efcf1c2a7..6d06ee179 100644 --- a/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c +++ b/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c @@ -601,9 +601,12 @@ typedef struct { } rt_enumerator_t; METHOD(enumerator_t, rt_enumerate, bool, - rt_enumerator_t *this, int *xtype, struct sockaddr **addr) + rt_enumerator_t *this, va_list args) { - int i, type; + struct sockaddr **addr; + int i, type, *xtype; + + VA_ARGS_VGET(args, xtype, addr); if (this->remaining < sizeof(this->addr->sa_len) || this->remaining < this->addr->sa_len) @@ -637,7 +640,8 @@ static enumerator_t *create_rt_enumerator(int types, int remaining, INIT(this, .public = { - .enumerate = (void*)_rt_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _rt_enumerate, .destroy = (void*)free, }, .types = types, @@ -1050,41 +1054,45 @@ typedef struct { kernel_address_type_t which; } address_enumerator_t; -/** - * cleanup function for address enumerator - */ -static void address_enumerator_destroy(address_enumerator_t *data) +CALLBACK(address_enumerator_destroy, void, + address_enumerator_t *data) { data->this->lock->unlock(data->this->lock); free(data); } -/** - * filter for addresses - */ -static bool filter_addresses(address_enumerator_t *data, - addr_entry_t** in, host_t** out) +CALLBACK(filter_addresses, bool, + address_enumerator_t *data, enumerator_t *orig, va_list args) { - host_t *ip; - if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->virtual) - { /* skip virtual interfaces added by us */ - return FALSE; - } - if (!(data->which & ADDR_TYPE_REGULAR) && !(*in)->virtual) - { /* address is regular, but not requested */ - return FALSE; - } - ip = (*in)->ip; - if (ip->get_family(ip) == AF_INET6) + addr_entry_t *addr; + host_t *ip, **out; + struct sockaddr_in6 *sin6; + + VA_ARGS_VGET(args, out); + + while (orig->enumerate(orig, &addr)) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ip->get_sockaddr(ip); - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) - { /* skip addresses with a unusable scope */ - return FALSE; + if (!(data->which & ADDR_TYPE_VIRTUAL) && addr->virtual) + { /* skip virtual interfaces added by us */ + continue; } + if (!(data->which & ADDR_TYPE_REGULAR) && !addr->virtual) + { /* address is regular, but not requested */ + continue; + } + ip = addr->ip; + if (ip->get_family(ip) == AF_INET6) + { + sin6 = (struct sockaddr_in6 *)ip->get_sockaddr(ip); + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + { /* skip addresses with a unusable scope */ + continue; + } + } + *out = ip; + return TRUE; } - *out = ip; - return TRUE; + return FALSE; } /** @@ -1094,29 +1102,34 @@ static enumerator_t *create_iface_enumerator(iface_entry_t *iface, address_enumerator_t *data) { return enumerator_create_filter(iface->addrs->create_enumerator(iface->addrs), - (void*)filter_addresses, data, NULL); + filter_addresses, data, NULL); } -/** - * filter for interfaces - */ -static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in, - iface_entry_t** out) +CALLBACK(filter_interfaces, bool, + address_enumerator_t *data, enumerator_t *orig, va_list args) { - if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable) - { /* skip interfaces excluded by config */ - return FALSE; - } - if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK)) - { /* ignore loopback devices */ - return FALSE; - } - if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP)) - { /* skip interfaces not up */ - return FALSE; + iface_entry_t *iface, **out; + + VA_ARGS_VGET(args, out); + + while (orig->enumerate(orig, &iface)) + { + if (!(data->which & ADDR_TYPE_IGNORED) && !iface->usable) + { /* skip interfaces excluded by config */ + continue; + } + if (!(data->which & ADDR_TYPE_LOOPBACK) && (iface->flags & IFF_LOOPBACK)) + { /* ignore loopback devices */ + continue; + } + if (!(data->which & ADDR_TYPE_DOWN) && !(iface->flags & IFF_UP)) + { /* skip interfaces not up */ + continue; + } + *out = iface; + return TRUE; } - *out = *in; - return TRUE; + return FALSE; } METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, @@ -1133,9 +1146,9 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, return enumerator_create_nested( enumerator_create_filter( this->ifaces->create_enumerator(this->ifaces), - (void*)filter_interfaces, data, NULL), + filter_interfaces, data, NULL), (void*)create_iface_enumerator, data, - (void*)address_enumerator_destroy); + address_enumerator_destroy); } METHOD(kernel_net_t, get_features, kernel_feature_t, @@ -1789,13 +1802,18 @@ METHOD(enumerator_t, destroy_subnet_enumerator, void, } METHOD(enumerator_t, enumerate_subnets, bool, - subnet_enumerator_t *this, host_t **net, uint8_t *mask, char **ifname) + subnet_enumerator_t *this, va_list args) { enumerator_t *enumerator; + host_t **net; struct rt_msghdr *rtm; struct sockaddr *addr; + uint8_t *mask; + char **ifname; int type; + VA_ARGS_VGET(args, net, mask, ifname); + if (!this->current) { this->current = this->buf; @@ -1888,7 +1906,8 @@ METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_enumerate_subnets, + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate_subnets, .destroy = _destroy_subnet_enumerator, }, .buf = buf, diff --git a/src/libcharon/plugins/kernel_wfp/Makefile.in b/src/libcharon/plugins/kernel_wfp/Makefile.in index a3368d56f..ffdae84c0 100644 --- a/src/libcharon/plugins/kernel_wfp/Makefile.in +++ b/src/libcharon/plugins/kernel_wfp/Makefile.in @@ -366,6 +366,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -388,6 +389,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/led/Makefile.in b/src/libcharon/plugins/led/Makefile.in index f16304dbc..7f820292d 100644 --- a/src/libcharon/plugins/led/Makefile.in +++ b/src/libcharon/plugins/led/Makefile.in @@ -355,6 +355,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/load_tester/Makefile.in b/src/libcharon/plugins/load_tester/Makefile.in index c6e17fb83..c55e3578c 100644 --- a/src/libcharon/plugins/load_tester/Makefile.in +++ b/src/libcharon/plugins/load_tester/Makefile.in @@ -368,6 +368,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -390,6 +391,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/load_tester/load_tester_creds.c b/src/libcharon/plugins/load_tester/load_tester_creds.c index 2f482962a..2cedd130e 100644 --- a/src/libcharon/plugins/load_tester/load_tester_creds.c +++ b/src/libcharon/plugins/load_tester/load_tester_creds.c @@ -395,22 +395,28 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, return NULL; } -/** - * Filter function for shared keys, returning ID matches - */ -static bool shared_filter(void *null, shared_key_t **in, shared_key_t **out, - void **un1, id_match_t *me, void **un2, id_match_t *other) +CALLBACK(shared_filter, bool, + void *null, enumerator_t *orig, va_list args) { - *out = *in; - if (me) - { - *me = ID_MATCH_ANY; - } - if (other) + shared_key_t *key, **out; + id_match_t *me, *other; + + VA_ARGS_VGET(args, out, me, other); + + if (orig->enumerate(orig, &key)) { - *other = ID_MATCH_ANY; + *out = key; + if (me) + { + *me = ID_MATCH_ANY; + } + if (other) + { + *other = ID_MATCH_ANY; + } + return TRUE; } - return TRUE; + return FALSE; } METHOD(credential_set_t, create_shared_enumerator, enumerator_t*, @@ -431,7 +437,7 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*, return NULL; } return enumerator_create_filter(enumerator_create_single(shared, NULL), - (void*)shared_filter, NULL, NULL); + shared_filter, NULL, NULL); } METHOD(load_tester_creds_t, destroy, void, diff --git a/src/libcharon/plugins/lookip/Makefile.in b/src/libcharon/plugins/lookip/Makefile.in index 919060469..ba86d3788 100644 --- a/src/libcharon/plugins/lookip/Makefile.in +++ b/src/libcharon/plugins/lookip/Makefile.in @@ -364,6 +364,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -386,6 +387,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/medcli/Makefile.in b/src/libcharon/plugins/medcli/Makefile.in index 4db68a3fc..e2d63be1c 100644 --- a/src/libcharon/plugins/medcli/Makefile.in +++ b/src/libcharon/plugins/medcli/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index 78159c845..f34990176 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -223,10 +223,11 @@ typedef struct { } peer_enumerator_t; METHOD(enumerator_t, peer_enumerator_enumerate, bool, - peer_enumerator_t *this, peer_cfg_t **cfg) + peer_enumerator_t *this, va_list args) { char *name, *local_net, *remote_net; chunk_t me, other; + peer_cfg_t **cfg; child_cfg_t *child_cfg; auth_cfg_t *auth; peer_cfg_create_t peer = { @@ -249,6 +250,8 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, .mode = MODE_TUNNEL, }; + VA_ARGS_VGET(args, cfg); + DESTROY_IF(this->current); if (!this->inner->enumerate(this->inner, &name, &me, &other, &local_net, &remote_net)) @@ -295,7 +298,8 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_peer_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _peer_enumerator_enumerate, .destroy = _peer_enumerator_destroy, }, .ike = this->ike, diff --git a/src/libcharon/plugins/medcli/medcli_creds.c b/src/libcharon/plugins/medcli/medcli_creds.c index 677229b9f..528fc004d 100644 --- a/src/libcharon/plugins/medcli/medcli_creds.c +++ b/src/libcharon/plugins/medcli/medcli_creds.c @@ -50,10 +50,13 @@ typedef struct { } private_enumerator_t; METHOD(enumerator_t, private_enumerator_enumerate, bool, - private_enumerator_t *this, private_key_t **key) + private_enumerator_t *this, va_list args) { + private_key_t **key; chunk_t chunk; + VA_ARGS_VGET(args, key); + DESTROY_IF(this->current); while (this->inner->enumerate(this->inner, &chunk)) { @@ -92,7 +95,8 @@ METHOD(credential_set_t, create_private_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_private_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _private_enumerator_enumerate, .destroy = _private_enumerator_destroy, }, ); @@ -123,11 +127,14 @@ typedef struct { } cert_enumerator_t; METHOD(enumerator_t, cert_enumerator_enumerate, bool, - cert_enumerator_t *this, certificate_t **cert) + cert_enumerator_t *this, va_list args) { + certificate_t **cert; public_key_t *public; chunk_t chunk; + VA_ARGS_VGET(args, cert); + DESTROY_IF(this->current); while (this->inner->enumerate(this->inner, &chunk)) { @@ -180,7 +187,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_cert_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _cert_enumerator_enumerate, .destroy = _cert_enumerator_destroy, }, .type = key, diff --git a/src/libcharon/plugins/medcli/medcli_creds.h b/src/libcharon/plugins/medcli/medcli_creds.h index 4b5402653..ec17955a2 100644 --- a/src/libcharon/plugins/medcli/medcli_creds.h +++ b/src/libcharon/plugins/medcli/medcli_creds.h @@ -37,7 +37,7 @@ struct medcli_creds_t { credential_set_t set; /** - * Destroy the credentials databse. + * Destroy the credentials database. */ void (*destroy)(medcli_creds_t *this); }; diff --git a/src/libcharon/plugins/medcli/medcli_listener.h b/src/libcharon/plugins/medcli/medcli_listener.h index 4768beccd..860dcdc60 100644 --- a/src/libcharon/plugins/medcli/medcli_listener.h +++ b/src/libcharon/plugins/medcli/medcli_listener.h @@ -37,7 +37,7 @@ struct medcli_listener_t { listener_t listener; /** - * Destroy the credentials databse. + * Destroy the credentials database. */ void (*destroy)(medcli_listener_t *this); }; diff --git a/src/libcharon/plugins/medsrv/Makefile.in b/src/libcharon/plugins/medsrv/Makefile.in index ceb06deb1..10b48daa3 100644 --- a/src/libcharon/plugins/medsrv/Makefile.in +++ b/src/libcharon/plugins/medsrv/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/medsrv/medsrv_creds.c b/src/libcharon/plugins/medsrv/medsrv_creds.c index 0d99c4f77..16d4bd7f3 100644 --- a/src/libcharon/plugins/medsrv/medsrv_creds.c +++ b/src/libcharon/plugins/medsrv/medsrv_creds.c @@ -52,12 +52,14 @@ typedef struct { } cert_enumerator_t; METHOD(enumerator_t, cert_enumerator_enumerate, bool, - cert_enumerator_t *this, certificate_t **cert) + cert_enumerator_t *this, va_list args) { - certificate_t *trusted; + certificate_t *trusted, **cert; public_key_t *public; chunk_t chunk; + VA_ARGS_VGET(args, cert); + DESTROY_IF(this->current); while (this->inner->enumerate(this->inner, &chunk)) { @@ -110,7 +112,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_cert_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _cert_enumerator_enumerate, .destroy = _cert_enumerator_destroy, }, .type = key, diff --git a/src/libcharon/plugins/medsrv/medsrv_creds.h b/src/libcharon/plugins/medsrv/medsrv_creds.h index 2079601af..08ecaa3f2 100644 --- a/src/libcharon/plugins/medsrv/medsrv_creds.h +++ b/src/libcharon/plugins/medsrv/medsrv_creds.h @@ -37,7 +37,7 @@ struct medsrv_creds_t { credential_set_t set; /** - * Destroy the credentials databse. + * Destroy the credentials database. */ void (*destroy)(medsrv_creds_t *this); }; diff --git a/src/libcharon/plugins/osx_attr/Makefile.in b/src/libcharon/plugins/osx_attr/Makefile.in index ab9ece561..8e0b10eb0 100644 --- a/src/libcharon/plugins/osx_attr/Makefile.in +++ b/src/libcharon/plugins/osx_attr/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/osx_attr/osx_attr_handler.c b/src/libcharon/plugins/osx_attr/osx_attr_handler.c index 6baf76d35..e7a627b93 100644 --- a/src/libcharon/plugins/osx_attr/osx_attr_handler.c +++ b/src/libcharon/plugins/osx_attr/osx_attr_handler.c @@ -218,12 +218,15 @@ METHOD(attribute_handler_t, release, void, } METHOD(enumerator_t, enumerate_dns, bool, - enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data) + enumerator_t *this, va_list args) { + configuration_attribute_type_t *type; + chunk_t *data; + + VA_ARGS_VGET(args, type, data); *type = INTERNAL_IP4_DNS; *data = chunk_empty; - /* stop enumeration */ - this->enumerate = (void*)return_false; + this->venumerate = (void*)return_false; return TRUE; } @@ -234,7 +237,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, enumerator_t *enumerator; INIT(enumerator, - .enumerate = (void*)_enumerate_dns, + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate_dns, .destroy = (void*)free, ); return enumerator; diff --git a/src/libcharon/plugins/p_cscf/Makefile.in b/src/libcharon/plugins/p_cscf/Makefile.in index 7b3cb2fa4..954a43dc8 100644 --- a/src/libcharon/plugins/p_cscf/Makefile.in +++ b/src/libcharon/plugins/p_cscf/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/p_cscf/p_cscf_handler.c b/src/libcharon/plugins/p_cscf/p_cscf_handler.c index 76633845e..cdf266054 100644 --- a/src/libcharon/plugins/p_cscf/p_cscf_handler.c +++ b/src/libcharon/plugins/p_cscf/p_cscf_handler.c @@ -83,9 +83,12 @@ typedef struct { } attr_enumerator_t; METHOD(enumerator_t, enumerate_attrs, bool, - attr_enumerator_t *this, configuration_attribute_type_t *type, - chunk_t *data) + attr_enumerator_t *this, va_list args) { + configuration_attribute_type_t *type; + chunk_t *data; + + VA_ARGS_VGET(args, type, data); if (this->request_ipv4) { *type = P_CSCF_IP4_ADDRESS; @@ -103,12 +106,13 @@ METHOD(enumerator_t, enumerate_attrs, bool, return FALSE; } -/** - * Check if the given host has a matching address family - */ -static bool is_family(host_t *host, int *family) +CALLBACK(is_family, bool, + host_t *host, va_list args) { - return host->get_family(host) == *family; + int family; + + VA_ARGS_VGET(args, family); + return host->get_family(host) == family; } /** @@ -116,7 +120,7 @@ static bool is_family(host_t *host, int *family) */ static bool has_host_family(linked_list_t *list, int family) { - return list->find_first(list, (void*)is_family, NULL, &family) == SUCCESS; + return list->find_first(list, is_family, NULL, family); } METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, @@ -132,7 +136,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, INIT(enumerator, .public = { - .enumerate = (void*)_enumerate_attrs, + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate_attrs, .destroy = (void*)free, }, ); diff --git a/src/libcharon/plugins/radattr/Makefile.in b/src/libcharon/plugins/radattr/Makefile.in index 1fe3033dc..add1f547f 100644 --- a/src/libcharon/plugins/radattr/Makefile.in +++ b/src/libcharon/plugins/radattr/Makefile.in @@ -359,6 +359,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/resolve/Makefile.in b/src/libcharon/plugins/resolve/Makefile.in index f8b62edf2..5e166f28f 100644 --- a/src/libcharon/plugins/resolve/Makefile.in +++ b/src/libcharon/plugins/resolve/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/resolve/resolve_handler.c b/src/libcharon/plugins/resolve/resolve_handler.c index 9077b51d4..05b865464 100644 --- a/src/libcharon/plugins/resolve/resolve_handler.c +++ b/src/libcharon/plugins/resolve/resolve_handler.c @@ -391,10 +391,13 @@ typedef struct { bool v6; } attribute_enumerator_t; -static bool attribute_enumerate(attribute_enumerator_t *this, - configuration_attribute_type_t *type, - chunk_t *data) +METHOD(enumerator_t, attribute_enumerate, bool, + attribute_enumerator_t *this, va_list args) { + configuration_attribute_type_t *type; + chunk_t *data; + + VA_ARGS_VGET(args, type, data); if (this->v4) { *type = INTERNAL_IP4_DNS; @@ -443,7 +446,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)attribute_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _attribute_enumerate, .destroy = (void*)free, }, .v4 = has_host_family(vips, AF_INET), diff --git a/src/libcharon/plugins/smp/Makefile.in b/src/libcharon/plugins/smp/Makefile.in index bf0791c42..9aac31894 100644 --- a/src/libcharon/plugins/smp/Makefile.in +++ b/src/libcharon/plugins/smp/Makefile.in @@ -356,6 +356,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/socket_default/Makefile.in b/src/libcharon/plugins/socket_default/Makefile.in index f66ae1679..b87afa4a6 100644 --- a/src/libcharon/plugins/socket_default/Makefile.in +++ b/src/libcharon/plugins/socket_default/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c index ba22b0c2b..109b3fe9b 100644 --- a/src/libcharon/plugins/socket_default/socket_default_socket.c +++ b/src/libcharon/plugins/socket_default/socket_default_socket.c @@ -142,6 +142,11 @@ struct private_socket_default_socket_t { bool set_source; /** + * TRUE to force sending source interface on outbound packetrs + */ + bool set_sourceif; + + /** * A counter to implement round-robin selection of read sockets */ u_int rr_counter; @@ -362,12 +367,33 @@ static ssize_t send_msg_generic(int skt, struct msghdr *msg) return sendmsg(skt, msg, 0); } +#if defined(IP_PKTINFO) || defined(HAVE_IN6_PKTINFO) + +/** + * Find the interface index a source address is installed on + */ +static int find_srcif(host_t *src) +{ + char *ifname; + int idx = 0; + + if (charon->kernel->get_interface(charon->kernel, src, &ifname)) + { + idx = if_nametoindex(ifname); + free(ifname); + } + return idx; +} + +#endif /* IP_PKTINFO || HAVE_IN6_PKTINFO */ + /** * Send a message with the IPv4 source address set, if possible. */ #ifdef IP_PKTINFO -static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) +static ssize_t send_msg_v4(private_socket_default_socket_t *this, int skt, + struct msghdr *msg, host_t *src) { char buf[CMSG_SPACE(sizeof(struct in_pktinfo))] = {}; struct cmsghdr *cmsg; @@ -383,6 +409,10 @@ static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); + if (this->set_sourceif) + { + pktinfo->ipi_ifindex = find_srcif(src); + } addr = &pktinfo->ipi_spec_dst; sin = (struct sockaddr_in*)src->get_sockaddr(src); @@ -392,7 +422,8 @@ static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) #elif defined(IP_SENDSRCADDR) -static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) +static ssize_t send_msg_v4(private_socket_default_socket_t *this, int skt, + struct msghdr *msg, host_t *src) { char buf[CMSG_SPACE(sizeof(struct in_addr))] = {}; struct cmsghdr *cmsg; @@ -415,7 +446,8 @@ static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) #else /* IP_PKTINFO || IP_RECVDSTADDR */ -static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) +static ssize_t send_msg_v4(private_socket_default_socket_t *this, + int skt, struct msghdr *msg, host_t *src) { return send_msg_generic(skt, msg); } @@ -427,7 +459,8 @@ static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) */ #ifdef HAVE_IN6_PKTINFO -static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src) +static ssize_t send_msg_v6(private_socket_default_socket_t *this, int skt, + struct msghdr *msg, host_t *src) { char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {}; struct cmsghdr *cmsg; @@ -441,6 +474,10 @@ static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src) cmsg->cmsg_type = IPV6_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg); + if (this->set_sourceif) + { + pktinfo->ipi6_ifindex = find_srcif(src); + } sin = (struct sockaddr_in6*)src->get_sockaddr(src); memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr)); return send_msg_generic(skt, msg); @@ -448,7 +485,8 @@ static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src) #else /* HAVE_IN6_PKTINFO */ -static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src) +static ssize_t send_msg_v6(private_socket_default_socket_t *this, + int skt, struct msghdr *msg, host_t *src) { return send_msg_generic(skt, msg); } @@ -564,11 +602,11 @@ METHOD(socket_t, sender, status_t, { if (family == AF_INET) { - bytes_sent = send_msg_v4(skt, &msg, src); + bytes_sent = send_msg_v4(this, skt, &msg, src); } else { - bytes_sent = send_msg_v6(skt, &msg, src); + bytes_sent = send_msg_v6(this, skt, &msg, src); } } else @@ -831,6 +869,9 @@ socket_default_socket_t *socket_default_socket_create() .set_source = lib->settings->get_bool(lib->settings, "%s.plugins.socket-default.set_source", TRUE, lib->ns), + .set_sourceif = lib->settings->get_bool(lib->settings, + "%s.plugins.socket-default.set_sourceif", FALSE, + lib->ns), ); if (this->port && this->port == this->natt) diff --git a/src/libcharon/plugins/socket_dynamic/Makefile.in b/src/libcharon/plugins/socket_dynamic/Makefile.in index 3d07b5407..595651f21 100644 --- a/src/libcharon/plugins/socket_dynamic/Makefile.in +++ b/src/libcharon/plugins/socket_dynamic/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/socket_win/Makefile.in b/src/libcharon/plugins/socket_win/Makefile.in index 692489845..8f1e43926 100644 --- a/src/libcharon/plugins/socket_win/Makefile.in +++ b/src/libcharon/plugins/socket_win/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/sql/Makefile.in b/src/libcharon/plugins/sql/Makefile.in index 581225b55..5c146190d 100644 --- a/src/libcharon/plugins/sql/Makefile.in +++ b/src/libcharon/plugins/sql/Makefile.in @@ -356,6 +356,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index 88cac7f26..00ed693eb 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -173,7 +173,8 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) child_cfg_create_t child = { .mode = mode, .reqid = reqid, - .ipcomp = ipcomp, + .options = (ipcomp ? OPT_IPCOMP : 0) | + (hostaccess ? OPT_HOSTACCESS : 0), .lifetime = { .time = { .life = lifetime, .rekey = rekeytime, .jitter = jitter @@ -183,7 +184,6 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) .dpd_action = dpd, .close_action = close, .updown = updown, - .hostaccess = hostaccess, }; child_cfg = child_cfg_create(name, &child); add_esp_proposals(this, child_cfg, id); @@ -504,11 +504,12 @@ typedef struct { ike_cfg_t *current; } ike_enumerator_t; -/** - * Implementation of ike_enumerator_t.public.enumerate - */ -static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg) +METHOD(enumerator_t, ike_enumerator_enumerate, bool, + ike_enumerator_t *this, va_list args) { + ike_cfg_t **cfg; + + VA_ARGS_VGET(args, cfg); DESTROY_IF(this->current); this->current = build_ike_cfg(this->this, this->inner, this->me, this->other); if (this->current) @@ -519,10 +520,8 @@ static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg) return FALSE; } -/** - * Implementation of ike_enumerator_t.public.destroy - */ -static void ike_enumerator_destroy(ike_enumerator_t *this) +METHOD(enumerator_t, ike_enumerator_destroy, void, + ike_enumerator_t *this) { DESTROY_IF(this->current); this->inner->destroy(this->inner); @@ -532,19 +531,22 @@ static void ike_enumerator_destroy(ike_enumerator_t *this) METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*, private_sql_config_t *this, host_t *me, host_t *other) { - ike_enumerator_t *e = malloc_thing(ike_enumerator_t); - - e->this = this; - e->me = me; - e->other = other; - e->current = NULL; - e->public.enumerate = (void*)ike_enumerator_enumerate; - e->public.destroy = (void*)ike_enumerator_destroy; + ike_enumerator_t *e; + INIT(e, + .public = { + .enumerate = enumerator_enumerate_default, + .venumerate = _ike_enumerator_enumerate, + .destroy = _ike_enumerator_destroy, + }, + .this = this, + .me = me, + .other = other, + ); e->inner = this->db->query(this->db, - "SELECT id, certreq, force_encap, local, remote " - "FROM ike_configs", - DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT); + "SELECT id, certreq, force_encap, local, remote " + "FROM ike_configs", + DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT); if (!e->inner) { free(e); @@ -569,11 +571,12 @@ typedef struct { peer_cfg_t *current; } peer_enumerator_t; -/** - * Implementation of peer_enumerator_t.public.enumerate - */ -static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) +METHOD(enumerator_t, peer_enumerator_enumerate, bool, + peer_enumerator_t *this, va_list args) { + peer_cfg_t **cfg; + + VA_ARGS_VGET(args, cfg); DESTROY_IF(this->current); this->current = build_peer_cfg(this->this, this->inner, this->me, this->other); if (this->current) @@ -584,10 +587,8 @@ static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) return FALSE; } -/** - * Implementation of peer_enumerator_t.public.destroy - */ -static void peer_enumerator_destroy(peer_enumerator_t *this) +METHOD(enumerator_t, peer_enumerator_destroy, void, + peer_enumerator_t *this) { DESTROY_IF(this->current); this->inner->destroy(this->inner); @@ -597,14 +598,18 @@ static void peer_enumerator_destroy(peer_enumerator_t *this) METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, private_sql_config_t *this, identification_t *me, identification_t *other) { - peer_enumerator_t *e = malloc_thing(peer_enumerator_t); - - e->this = this; - e->me = me; - e->other = other; - e->current = NULL; - e->public.enumerate = (void*)peer_enumerator_enumerate; - e->public.destroy = (void*)peer_enumerator_destroy; + peer_enumerator_t *e; + + INIT(e, + .public = { + .enumerate = enumerator_enumerate_default, + .venumerate = _peer_enumerator_enumerate, + .destroy = _peer_enumerator_destroy, + }, + .this = this, + .me = me, + .other = other, + ); /* TODO: only get configs whose IDs match exactly or contain wildcards */ e->inner = this->db->query(this->db, diff --git a/src/libcharon/plugins/sql/sql_cred.c b/src/libcharon/plugins/sql/sql_cred.c index 117eec921..3317de6c8 100644 --- a/src/libcharon/plugins/sql/sql_cred.c +++ b/src/libcharon/plugins/sql/sql_cred.c @@ -52,11 +52,14 @@ typedef struct { } private_enumerator_t; METHOD(enumerator_t, private_enumerator_enumerate, bool, - private_enumerator_t *this, private_key_t **key) + private_enumerator_t *this, va_list args) { + private_key_t **key; chunk_t blob; int type; + VA_ARGS_VGET(args, key); + DESTROY_IF(this->current); while (this->inner->enumerate(this->inner, &type, &blob)) { @@ -88,7 +91,8 @@ METHOD(credential_set_t, create_private_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_private_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _private_enumerator_enumerate, .destroy = _private_enumerator_destroy, }, ); @@ -132,11 +136,14 @@ typedef struct { } cert_enumerator_t; METHOD(enumerator_t, cert_enumerator_enumerate, bool, - cert_enumerator_t *this, certificate_t **cert) + cert_enumerator_t *this, va_list args) { + certificate_t **cert; chunk_t blob; int type; + VA_ARGS_VGET(args, cert); + DESTROY_IF(this->current); while (this->inner->enumerate(this->inner, &type, &blob)) { @@ -169,7 +176,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_cert_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _cert_enumerator_enumerate, .destroy = _cert_enumerator_destroy, }, ); @@ -221,12 +229,15 @@ typedef struct { } shared_enumerator_t; METHOD(enumerator_t, shared_enumerator_enumerate, bool, - shared_enumerator_t *this, shared_key_t **shared, - id_match_t *me, id_match_t *other) + shared_enumerator_t *this, va_list args) { + shared_key_t **shared; + id_match_t *me, *other; chunk_t blob; int type; + VA_ARGS_VGET(args, shared, me, other); + DESTROY_IF(this->current); while (this->inner->enumerate(this->inner, &type, &blob)) { @@ -265,7 +276,8 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_shared_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _shared_enumerator_enumerate, .destroy = _shared_enumerator_destroy, }, .me = me, @@ -340,9 +352,11 @@ typedef enum { } cdp_type_t; METHOD(enumerator_t, cdp_enumerator_enumerate, bool, - cdp_enumerator_t *this, char **uri) + cdp_enumerator_t *this, va_list args) { - char *text; + char *text, **uri; + + VA_ARGS_VGET(args, uri); free(this->current); while (this->inner->enumerate(this->inner, &text)) @@ -384,7 +398,8 @@ METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*, } INIT(e, .public = { - .enumerate = (void*)_cdp_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _cdp_enumerator_enumerate, .destroy = _cdp_enumerator_destroy, }, ); diff --git a/src/libcharon/plugins/stroke/Makefile.in b/src/libcharon/plugins/stroke/Makefile.in index 50a6d5953..0af607fd7 100644 --- a/src/libcharon/plugins/stroke/Makefile.in +++ b/src/libcharon/plugins/stroke/Makefile.in @@ -360,6 +360,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/stroke/stroke_attribute.c b/src/libcharon/plugins/stroke/stroke_attribute.c index cd1b4d093..7835031c2 100644 --- a/src/libcharon/plugins/stroke/stroke_attribute.c +++ b/src/libcharon/plugins/stroke/stroke_attribute.c @@ -178,28 +178,32 @@ METHOD(attribute_provider_t, release_address, bool, return found; } -/** - * Filter function to convert host to DNS configuration attributes - */ -static bool attr_filter(void *lock, host_t **in, - configuration_attribute_type_t *type, - void *dummy, chunk_t *data) +CALLBACK(attr_filter, bool, + void *lock, enumerator_t *orig, va_list args) { - host_t *host = *in; + configuration_attribute_type_t *type; + chunk_t *data; + host_t *host; - switch (host->get_family(host)) + VA_ARGS_VGET(args, type, data); + + while (orig->enumerate(orig, &host)) { - case AF_INET: - *type = INTERNAL_IP4_DNS; - break; - case AF_INET6: - *type = INTERNAL_IP6_DNS; - break; - default: - return FALSE; + switch (host->get_family(host)) + { + case AF_INET: + *type = INTERNAL_IP4_DNS; + break; + case AF_INET6: + *type = INTERNAL_IP6_DNS; + break; + default: + continue; + } + *data = host->get_address(host); + return TRUE; } - *data = host->get_address(host); - return TRUE; + return FALSE; } METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, @@ -223,7 +227,7 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, enumerator->destroy(enumerator); return enumerator_create_filter( attr->dns->create_enumerator(attr->dns), - (void*)attr_filter, this->lock, + attr_filter, this->lock, (void*)this->lock->unlock); } } @@ -338,24 +342,28 @@ METHOD(stroke_attribute_t, del_dns, void, this->lock->unlock(this->lock); } -/** - * Pool enumerator filter function, converts pool_t to name, size, ... - */ -static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name, - void *d1, u_int *size, void *d2, u_int *online, - void *d3, u_int *offline) +CALLBACK(pool_filter, bool, + void *lock, enumerator_t *orig, va_list args) { - mem_pool_t *pool = *poolp; + mem_pool_t *pool; + const char **name; + u_int *size, *online, *offline; - if (pool->get_size(pool) == 0) + VA_ARGS_VGET(args, name, size, online, offline); + + while (orig->enumerate(orig, &pool)) { - return FALSE; + if (pool->get_size(pool) == 0) + { + continue; + } + *name = pool->get_name(pool); + *size = pool->get_size(pool); + *online = pool->get_online(pool); + *offline = pool->get_offline(pool); + return TRUE; } - *name = pool->get_name(pool); - *size = pool->get_size(pool); - *online = pool->get_online(pool); - *offline = pool->get_offline(pool); - return TRUE; + return FALSE; } METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*, @@ -363,7 +371,7 @@ METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*, { this->lock->read_lock(this->lock); return enumerator_create_filter(this->pools->create_enumerator(this->pools), - (void*)pool_filter, + pool_filter, this->lock, (void*)this->lock->unlock); } diff --git a/src/libcharon/plugins/stroke/stroke_ca.c b/src/libcharon/plugins/stroke/stroke_ca.c index 13ed41e0e..4593e9bdc 100644 --- a/src/libcharon/plugins/stroke/stroke_ca.c +++ b/src/libcharon/plugins/stroke/stroke_ca.c @@ -171,26 +171,30 @@ typedef struct { identification_t *id; } cert_data_t; -/** - * destroy cert_data - */ -static void cert_data_destroy(cert_data_t *data) +CALLBACK(cert_data_destroy, void, + cert_data_t *data) { data->this->lock->unlock(data->this->lock); free(data); } -/** - * filter function for certs enumerator - */ -static bool certs_filter(cert_data_t *data, ca_cert_t **in, - certificate_t **out) +CALLBACK(certs_filter, bool, + cert_data_t *data, enumerator_t *orig, va_list args) { + ca_cert_t *cacert; public_key_t *public; - certificate_t *cert = (*in)->cert; + certificate_t **out; + + VA_ARGS_VGET(args, out); - if (data->cert == CERT_ANY || data->cert == cert->get_type(cert)) + while (orig->enumerate(orig, &cacert)) { + certificate_t *cert = cacert->cert; + + if (data->cert != CERT_ANY && data->cert != cert->get_type(cert)) + { + continue; + } public = cert->get_public_key(cert); if (public) { @@ -208,9 +212,9 @@ static bool certs_filter(cert_data_t *data, ca_cert_t **in, } else if (data->key != KEY_ANY) { - return FALSE; + continue; } - if (data->id == NULL || cert->has_subject(cert, data->id)) + if (!data->id || cert->has_subject(cert, data->id)) { *out = cert; return TRUE; @@ -235,8 +239,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, this->lock->read_lock(this->lock); enumerator = this->certs->create_enumerator(this->certs); - return enumerator_create_filter(enumerator, (void*)certs_filter, data, - (void*)cert_data_destroy); + return enumerator_create_filter(enumerator, certs_filter, data, + cert_data_destroy); } /** @@ -354,11 +358,12 @@ METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*, data, (void*)cdp_data_destroy); } -/** - * Compare the given certificate to the ca_cert_t items in the list - */ -static bool match_cert(ca_cert_t *item, certificate_t *cert) +CALLBACK(match_cert, bool, + ca_cert_t *item, va_list args) { + certificate_t *cert; + + VA_ARGS_VGET(args, cert); return cert->equals(cert, item->cert); } @@ -405,8 +410,7 @@ static certificate_t *add_cert_internal(private_stroke_ca_t *this, { ca_cert_t *found; - if (this->certs->find_first(this->certs, (linked_list_match_t)match_cert, - (void**)&found, cert) == SUCCESS) + if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert)) { cert->destroy(cert); cert = found->cert->get_ref(found->cert); @@ -511,8 +515,7 @@ METHOD(stroke_ca_t, get_cert_ref, certificate_t*, ca_cert_t *found; this->lock->read_lock(this->lock); - if (this->certs->find_first(this->certs, (linked_list_match_t)match_cert, - (void**)&found, cert) == SUCCESS) + if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert)) { cert->destroy(cert); cert = found->cert->get_ref(found->cert); diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index bbdc2116d..00f74831c 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -68,13 +68,20 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, (void*)this->mutex->unlock, this->mutex); } -/** - * filter function for ike configs - */ -static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out) +CALLBACK(ike_filter, bool, + void *data, enumerator_t *orig, va_list args) { - *out = (*in)->get_ike_cfg(*in); - return TRUE; + peer_cfg_t *cfg; + ike_cfg_t **out; + + VA_ARGS_VGET(args, out); + + if (orig->enumerate(orig, &cfg)) + { + *out = cfg->get_ike_cfg(cfg); + return TRUE; + } + return FALSE; } METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*, @@ -82,7 +89,7 @@ METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*, { this->mutex->lock(this->mutex); return enumerator_create_filter(this->list->create_enumerator(this->list), - (void*)ike_filter, this->mutex, + ike_filter, this->mutex, (void*)this->mutex->unlock); } @@ -1071,15 +1078,16 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, }, .reqid = msg->add_conn.reqid, .mode = msg->add_conn.mode, - .proxy_mode = msg->add_conn.proxy_mode, - .ipcomp = msg->add_conn.ipcomp, + .options = (msg->add_conn.proxy_mode ? OPT_PROXY_MODE : 0) | + (msg->add_conn.ipcomp ? OPT_IPCOMP : 0) | + (msg->add_conn.me.hostaccess ? OPT_HOSTACCESS : 0) | + (msg->add_conn.install_policy ? 0 : OPT_NO_POLICIES) | + (msg->add_conn.sha256_96 ? OPT_SHA256_96 : 0), .tfc = msg->add_conn.tfc, .inactivity = msg->add_conn.inactivity, .dpd_action = map_action(msg->add_conn.dpd.action), .close_action = map_action(msg->add_conn.close_action), .updown = msg->add_conn.me.updown, - .hostaccess = msg->add_conn.me.hostaccess, - .suppress_policies = !msg->add_conn.install_policy, }; child_cfg = child_cfg_create(msg->add_conn.name, &child); diff --git a/src/libcharon/plugins/stroke/stroke_handler.c b/src/libcharon/plugins/stroke/stroke_handler.c index d0cc9afab..19d5a62a1 100644 --- a/src/libcharon/plugins/stroke/stroke_handler.c +++ b/src/libcharon/plugins/stroke/stroke_handler.c @@ -62,35 +62,39 @@ static void attributes_destroy(attributes_t *this) free(this); } -/** - * Filter function to convert host to DNS configuration attributes - */ -static bool attr_filter(void *lock, host_t **in, - configuration_attribute_type_t *type, - void *dummy, chunk_t *data) +CALLBACK(attr_filter, bool, + void *lock, enumerator_t *orig, va_list args) { - host_t *host = *in; + configuration_attribute_type_t *type; + chunk_t *data; + host_t *host; - switch (host->get_family(host)) - { - case AF_INET: - *type = INTERNAL_IP4_DNS; - break; - case AF_INET6: - *type = INTERNAL_IP6_DNS; - break; - default: - return FALSE; - } - if (host->is_anyaddr(host)) - { - *data = chunk_empty; - } - else + VA_ARGS_VGET(args, type, data); + + while (orig->enumerate(orig, &host)) { - *data = host->get_address(host); + switch (host->get_family(host)) + { + case AF_INET: + *type = INTERNAL_IP4_DNS; + break; + case AF_INET6: + *type = INTERNAL_IP6_DNS; + break; + default: + continue; + } + if (host->is_anyaddr(host)) + { + *data = chunk_empty; + } + else + { + *data = host->get_address(host); + } + return TRUE; } - return TRUE; + return FALSE; } METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*, @@ -114,7 +118,7 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*, enumerator->destroy(enumerator); return enumerator_create_filter( attr->dns->create_enumerator(attr->dns), - (void*)attr_filter, this->lock, + attr_filter, this->lock, (void*)this->lock->unlock); } } diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index 92e368669..22992599d 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -218,7 +218,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa), child_sa_state_names, child_sa->get_state(child_sa), ipsec_mode_names, child_sa->get_mode(child_sa), - config->use_proxy_mode(config) ? "_PROXY" : "", + config->has_option(config, OPT_PROXY_MODE) ? "_PROXY" : "", child_sa->get_reqid(child_sa)); if (child_sa->get_state(child_sa) == CHILD_INSTALLED) @@ -958,8 +958,7 @@ static void list_plugins(FILE *out) { case FEATURE_PROVIDE: fp = &features[i]; - loaded = list->find_first(list, NULL, - (void**)&fp) == SUCCESS; + loaded = list->find_first(list, NULL, (void**)&fp); fprintf(out, " %s%s\n", str, loaded ? "" : " (not loaded)"); break; diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 46de90ca6..65d345db3 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -216,6 +216,7 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) DBG_OPT(" dpdtimeout=%d", msg->add_conn.dpd.timeout); DBG_OPT(" dpdaction=%d", msg->add_conn.dpd.action); DBG_OPT(" closeaction=%d", msg->add_conn.close_action); + DBG_OPT(" sha256_96=%s", msg->add_conn.sha256_96 ? "yes" : "no"); DBG_OPT(" mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); DBG_OPT(" mediated_by=%s", msg->add_conn.ikeme.mediated_by); DBG_OPT(" me_peerid=%s", msg->add_conn.ikeme.peerid); diff --git a/src/libcharon/plugins/systime_fix/Makefile.in b/src/libcharon/plugins/systime_fix/Makefile.in index 78fd6e8d1..327443020 100644 --- a/src/libcharon/plugins/systime_fix/Makefile.in +++ b/src/libcharon/plugins/systime_fix/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/tnc_ifmap/Makefile.in b/src/libcharon/plugins/tnc_ifmap/Makefile.in index 7ec4eaad1..438001baf 100644 --- a/src/libcharon/plugins/tnc_ifmap/Makefile.in +++ b/src/libcharon/plugins/tnc_ifmap/Makefile.in @@ -361,6 +361,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap_msg.c b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap_msg.c index b86288683..db19bd575 100644 --- a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap_msg.c +++ b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap_msg.c @@ -55,7 +55,7 @@ struct private_tnc_ifmap_soap_msg_t { static xmlNodePtr find_child(xmlNodePtr parent, const xmlChar* name) { xmlNodePtr child; - + child = parent->xmlChildrenNode; while (child) { @@ -80,7 +80,7 @@ METHOD(tnc_ifmap_soap_msg_t, post, bool, xmlChar *xml_str, *errorCode, *errorString; int xml_len, len, written; chunk_t xml, http; - char buf[4096]; + char buf[4096] = { 0 }; status_t status; DBG2(DBG_TNC, "sending ifmap %s", request->name); @@ -131,7 +131,8 @@ METHOD(tnc_ifmap_soap_msg_t, post, bool, xml = chunk_empty; do { - len = this->tls->read(this->tls, buf, sizeof(buf), TRUE); + /* reduce size so the buffer is null-terminated */ + len = this->tls->read(this->tls, buf, sizeof(buf)-1, TRUE); if (len <= 0) { return FALSE; @@ -150,7 +151,7 @@ METHOD(tnc_ifmap_soap_msg_t, post, bool, DBG3(DBG_TNC, "parsing XML message %B", &xml); this->doc = xmlParseMemory(xml.ptr, xml.len); free(xml.ptr); - + if (!this->doc) { DBG1(DBG_TNC, "failed to parse XML message"); diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.in b/src/libcharon/plugins/tnc_pdp/Makefile.in index 215e3b38e..abc77433a 100644 --- a/src/libcharon/plugins/tnc_pdp/Makefile.in +++ b/src/libcharon/plugins/tnc_pdp/Makefile.in @@ -362,6 +362,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -384,6 +385,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/uci/Makefile.in b/src/libcharon/plugins/uci/Makefile.in index 64b4bca24..46f4e4f85 100644 --- a/src/libcharon/plugins/uci/Makefile.in +++ b/src/libcharon/plugins/uci/Makefile.in @@ -356,6 +356,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index e0578fe9b..dcd4ae348 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -118,11 +118,12 @@ static u_int create_rekey(char *string) } METHOD(enumerator_t, peer_enumerator_enumerate, bool, - peer_enumerator_t *this, peer_cfg_t **cfg) + peer_enumerator_t *this, va_list args) { char *name, *ike_proposal, *esp_proposal, *ike_rekey, *esp_rekey; char *local_id, *local_addr, *local_net; char *remote_id, *remote_addr, *remote_net; + peer_cfg_t **cfg; child_cfg_t *child_cfg; ike_cfg_t *ike_cfg; auth_cfg_t *auth; @@ -145,6 +146,8 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, .mode = MODE_TUNNEL, }; + VA_ARGS_VGET(args, cfg); + /* defaults */ name = "unnamed"; local_id = NULL; @@ -212,7 +215,8 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_peer_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _peer_enumerator_enumerate, .destroy = _peer_enumerator_destroy, }, .inner = this->parser->create_section_enumerator(this->parser, @@ -241,10 +245,13 @@ typedef struct { } ike_enumerator_t; METHOD(enumerator_t, ike_enumerator_enumerate, bool, - ike_enumerator_t *this, ike_cfg_t **cfg) + ike_enumerator_t *this, va_list args) { + ike_cfg_t **cfg; char *local_addr, *remote_addr, *ike_proposal; + VA_ARGS_VGET(args, cfg); + /* defaults */ local_addr = "0.0.0.0"; remote_addr = "0.0.0.0"; @@ -282,7 +289,8 @@ METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_ike_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _ike_enumerator_enumerate, .destroy = _ike_enumerator_destroy, }, .inner = this->parser->create_section_enumerator(this->parser, diff --git a/src/libcharon/plugins/uci/uci_creds.c b/src/libcharon/plugins/uci/uci_creds.c index f5d5ace70..404a3e39f 100644 --- a/src/libcharon/plugins/uci/uci_creds.c +++ b/src/libcharon/plugins/uci/uci_creds.c @@ -52,12 +52,15 @@ typedef struct { } shared_enumerator_t; METHOD(enumerator_t, shared_enumerator_enumerate, bool, - shared_enumerator_t *this, shared_key_t **key, id_match_t *me, - id_match_t *other) + shared_enumerator_t *this, va_list args) { + shared_key_t **key; + id_match_t *me, *other; char *local_id, *remote_id, *psk; identification_t *local, *remote; + VA_ARGS_VGET(args, key, me, other); + while (TRUE) { /* defaults */ @@ -126,7 +129,8 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_shared_enumerator_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _shared_enumerator_enumerate, .destroy = _shared_enumerator_destroy, }, .me = me, diff --git a/src/libcharon/plugins/uci/uci_parser.c b/src/libcharon/plugins/uci/uci_parser.c index 2429e9e44..e847dd393 100644 --- a/src/libcharon/plugins/uci/uci_parser.c +++ b/src/libcharon/plugins/uci/uci_parser.c @@ -58,11 +58,10 @@ typedef struct { } section_enumerator_t; METHOD(enumerator_t, section_enumerator_enumerate, bool, - section_enumerator_t *this, ...) + section_enumerator_t *this, va_list args) { struct uci_element *element; char **value; - va_list args; int i; if (&this->current->list == this->list) @@ -70,8 +69,6 @@ METHOD(enumerator_t, section_enumerator_enumerate, bool, return FALSE; } - va_start(args, this); - value = va_arg(args, char**); if (value) { @@ -96,7 +93,6 @@ METHOD(enumerator_t, section_enumerator_enumerate, bool, *value = uci_to_option(element)->value; } } - va_end(args); this->current = list_to_element(this->current->list.next); return TRUE; @@ -124,7 +120,13 @@ METHOD(uci_parser_t, create_section_enumerator, enumerator_t*, i++; } va_end(args); - e = malloc(sizeof(section_enumerator_t) + sizeof(char*) * i); + INIT_EXTRA(e, sizeof(char*) * i, + .public = { + .enumerate = enumerator_enumerate_default, + .venumerate = _section_enumerator_enumerate, + .destroy = _section_enumerator_destroy, + }, + ); i = 0; va_start(args, this); do @@ -134,9 +136,6 @@ METHOD(uci_parser_t, create_section_enumerator, enumerator_t*, while (e->keywords[i++]); va_end(args); - e->public.enumerate = (void*)_section_enumerator_enumerate; - e->public.destroy = _section_enumerator_destroy; - /* load uci context */ e->ctx = uci_alloc_context(); if (uci_load(e->ctx, this->package, &e->package) != UCI_OK) diff --git a/src/libcharon/plugins/unity/Makefile.in b/src/libcharon/plugins/unity/Makefile.in index 6811eb737..245bbd471 100644 --- a/src/libcharon/plugins/unity/Makefile.in +++ b/src/libcharon/plugins/unity/Makefile.in @@ -357,6 +357,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/unity/unity_handler.c b/src/libcharon/plugins/unity/unity_handler.c index 25e0756b7..4a1478c6d 100644 --- a/src/libcharon/plugins/unity/unity_handler.c +++ b/src/libcharon/plugins/unity/unity_handler.c @@ -368,9 +368,12 @@ typedef struct { } attribute_enumerator_t; METHOD(enumerator_t, enumerate_attributes, bool, - attribute_enumerator_t *this, configuration_attribute_type_t *type, - chunk_t *data) + attribute_enumerator_t *this, va_list args) { + configuration_attribute_type_t *type; + chunk_t *data; + + VA_ARGS_VGET(args, type, data); if (this->i < countof(attributes)) { *type = attributes[this->i++]; @@ -393,7 +396,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, } INIT(enumerator, .public = { - .enumerate = (void*)_enumerate_attributes, + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate_attributes, .destroy = (void*)free, }, ); @@ -407,24 +411,27 @@ typedef struct { ike_sa_id_t *id; } include_filter_t; -/** - * Include enumerator filter function - */ -static bool include_filter(include_filter_t *data, - entry_t **entry, traffic_selector_t **ts) +CALLBACK(include_filter, bool, + include_filter_t *data, enumerator_t *orig, va_list args) { - if (data->id->equals(data->id, (*entry)->id)) + entry_t *entry; + traffic_selector_t **ts; + + VA_ARGS_VGET(args, ts); + + while (orig->enumerate(orig, &entry)) { - *ts = (*entry)->ts; - return TRUE; + if (data->id->equals(data->id, entry->id)) + { + *ts = entry->ts; + return TRUE; + } } return FALSE; } -/** - * Destroy include filter data, unlock mutex - */ -static void destroy_filter(include_filter_t *data) +CALLBACK(destroy_filter, void, + include_filter_t *data) { data->mutex->unlock(data->mutex); free(data); @@ -442,7 +449,7 @@ METHOD(unity_handler_t, create_include_enumerator, enumerator_t*, data->mutex->lock(data->mutex); return enumerator_create_filter( this->include->create_enumerator(this->include), - (void*)include_filter, data, (void*)destroy_filter); + include_filter, data, destroy_filter); } METHOD(unity_handler_t, destroy, void, diff --git a/src/libcharon/plugins/unity/unity_provider.c b/src/libcharon/plugins/unity/unity_provider.c index 07f5f9b61..b6a55648e 100644 --- a/src/libcharon/plugins/unity/unity_provider.c +++ b/src/libcharon/plugins/unity/unity_provider.c @@ -77,12 +77,15 @@ static void append_ts(bio_writer_t *writer, traffic_selector_t *ts) } METHOD(enumerator_t, attribute_enumerate, bool, - attribute_enumerator_t *this, configuration_attribute_type_t *type, - chunk_t *attr) + attribute_enumerator_t *this, va_list args) { + configuration_attribute_type_t *type; + chunk_t *attr; traffic_selector_t *ts; bio_writer_t *writer; + VA_ARGS_VGET(args, type, attr); + if (this->list->get_count(this->list) == 0) { return FALSE; @@ -183,7 +186,8 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, INIT(attr_enum, .public = { - .enumerate = (void*)_attribute_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _attribute_enumerate, .destroy = _attribute_destroy, }, .list = list, diff --git a/src/libcharon/plugins/updown/Makefile.in b/src/libcharon/plugins/updown/Makefile.in index 1a44e5566..ef0f33ce3 100644 --- a/src/libcharon/plugins/updown/Makefile.in +++ b/src/libcharon/plugins/updown/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c index 6a1581c85..bbefd6a02 100644 --- a/src/libcharon/plugins/updown/updown_listener.c +++ b/src/libcharon/plugins/updown/updown_listener.c @@ -366,7 +366,7 @@ static void invoke_once(private_updown_listener_t *this, ike_sa_t *ike_sa, push_env(envp, countof(envp), "PLUTO_IPCOMP=1"); } push_dns_env(this, ike_sa, envp, countof(envp)); - if (config->get_hostaccess(config)) + if (config->has_option(config, OPT_HOSTACCESS)) { push_env(envp, countof(envp), "PLUTO_HOST_ACCESS=1"); } diff --git a/src/libcharon/plugins/vici/Makefile.in b/src/libcharon/plugins/vici/Makefile.in index cdefbff79..fd2b89849 100644 --- a/src/libcharon/plugins/vici/Makefile.in +++ b/src/libcharon/plugins/vici/Makefile.in @@ -454,6 +454,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -476,6 +477,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 9bda949d0..f47f80cad 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -480,11 +480,12 @@ Load a certificate into the daemon. Load a private key into the daemon. { - type = <private key type, RSA|ECDSA> + type = <private key type, rsa|ecdsa|bliss|any> data = <PEM or DER encoded key data> } => { success = <yes or no> errmsg = <error string on failure> + id = <hex-encoded SHA-1 key identifier of the public key on success> } ### unload-key() ### diff --git a/src/libcharon/plugins/vici/perl/Makefile.in b/src/libcharon/plugins/vici/perl/Makefile.in index 385aa9775..0e9626aa3 100644 --- a/src/libcharon/plugins/vici/perl/Makefile.in +++ b/src/libcharon/plugins/vici/perl/Makefile.in @@ -272,6 +272,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -294,6 +295,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/vici/python/Makefile.in b/src/libcharon/plugins/vici/python/Makefile.in index f783d7068..7d5383290 100644 --- a/src/libcharon/plugins/vici/python/Makefile.in +++ b/src/libcharon/plugins/vici/python/Makefile.in @@ -294,6 +294,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -316,6 +317,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/vici/python/vici/protocol.py b/src/libcharon/plugins/vici/python/vici/protocol.py index 919231d43..370229463 100644 --- a/src/libcharon/plugins/vici/python/vici/protocol.py +++ b/src/libcharon/plugins/vici/python/vici/protocol.py @@ -62,7 +62,7 @@ class Packet(object): @classmethod def _named_request(cls, request_type, request, message=None): - requestdata = request.encode("UTF-8") + request = request.encode("UTF-8") payload = struct.pack("!BB", request_type, len(request)) + request if message is not None: return payload + message diff --git a/src/libcharon/plugins/vici/ruby/Makefile.in b/src/libcharon/plugins/vici/ruby/Makefile.in index 125f44ee1..5691a74d1 100644 --- a/src/libcharon/plugins/vici/ruby/Makefile.in +++ b/src/libcharon/plugins/vici/ruby/Makefile.in @@ -272,6 +272,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -294,6 +295,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ @@ -468,8 +470,8 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -@RUBY_GEMS_INSTALL_FALSE@install-data-local: @RUBY_GEMS_INSTALL_FALSE@uninstall-local: +@RUBY_GEMS_INSTALL_FALSE@install-data-local: clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am diff --git a/src/libcharon/plugins/vici/suites/test_message.c b/src/libcharon/plugins/vici/suites/test_message.c index 045e34fff..73bba239b 100644 --- a/src/libcharon/plugins/vici/suites/test_message.c +++ b/src/libcharon/plugins/vici/suites/test_message.c @@ -122,9 +122,14 @@ typedef struct { endecode_test_t *next; } endecode_enum_t; -static bool endecode_enumerate(endecode_enum_t *this, vici_type_t *type, - char **name, chunk_t *data) +METHOD(enumerator_t, endecode_enumerate, bool, + endecode_enum_t *this, va_list args) { + vici_type_t *type; + chunk_t *data; + char **name; + + VA_ARGS_VGET(args, type, name, data); if (this->next) { *type = this->next->type; @@ -149,7 +154,8 @@ static enumerator_t *endecode_create_enumerator(endecode_test_t *test) INIT(enumerator, .public = { - .enumerate = (void*)endecode_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _endecode_enumerate, .destroy = (void*)free, }, .next = test, diff --git a/src/libcharon/plugins/vici/vici_attribute.c b/src/libcharon/plugins/vici/vici_attribute.c index 4e1fa9708..ab765fa14 100644 --- a/src/libcharon/plugins/vici/vici_attribute.c +++ b/src/libcharon/plugins/vici/vici_attribute.c @@ -184,16 +184,22 @@ METHOD(attribute_provider_t, release_address, bool, return found; } -/** - * Filter mapping attribute_t to enumerated type/value arguments - */ -static bool attr_filter(void *data, attribute_t **attr, - configuration_attribute_type_t *type, - void *in, chunk_t *value) +CALLBACK(attr_filter, bool, + void *data, enumerator_t *orig, va_list args) { - *type = (*attr)->type; - *value = (*attr)->value; - return TRUE; + attribute_t *attr; + configuration_attribute_type_t *type; + chunk_t *value; + + VA_ARGS_VGET(args, type, value); + + if (orig->enumerate(orig, &attr)) + { + *type = attr->type; + *value = attr->value; + return TRUE; + } + return FALSE; } /** @@ -203,7 +209,7 @@ CALLBACK(create_nested, enumerator_t*, pool_t *pool, void *this) { return enumerator_create_filter(array_create_enumerator(pool->attrs), - (void*)attr_filter, NULL, NULL); + attr_filter, NULL, NULL); } /** diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 12497ec5e..0c355e3a0 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -141,13 +141,20 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, (void*)this->lock->unlock, this->lock); } -/** - * Enumerator filter function for ike configs - */ -static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out) +CALLBACK(ike_filter, bool, + void *data, enumerator_t *orig, va_list args) { - *out = (*in)->get_ike_cfg(*in); - return TRUE; + peer_cfg_t *cfg; + ike_cfg_t **out; + + VA_ARGS_VGET(args, out); + + if (orig->enumerate(orig, &cfg)) + { + *out = cfg->get_ike_cfg(cfg); + return TRUE; + } + return FALSE; } METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*, @@ -155,7 +162,7 @@ METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*, { this->lock->read_lock(this->lock); return enumerator_create_filter(this->conns->create_enumerator(this->conns), - (void*)ike_filter, this->lock, + ike_filter, this->lock, (void*)this->lock->unlock); } @@ -478,7 +485,6 @@ typedef struct { linked_list_t *remote_ts; uint32_t replay_window; bool policies; - bool policies_fwd_out; child_cfg_create_t cfg; } child_data_t; @@ -500,12 +506,12 @@ static void log_child_data(child_data_t *data, char *name) DBG2(DBG_CFG, " life_packets = %llu", cfg->lifetime.packets.life); DBG2(DBG_CFG, " rand_packets = %llu", cfg->lifetime.packets.jitter); DBG2(DBG_CFG, " updown = %s", cfg->updown); - DBG2(DBG_CFG, " hostaccess = %u", cfg->hostaccess); - DBG2(DBG_CFG, " ipcomp = %u", cfg->ipcomp); + DBG2(DBG_CFG, " hostaccess = %u", cfg->options & OPT_HOSTACCESS); + DBG2(DBG_CFG, " ipcomp = %u", cfg->options & OPT_IPCOMP); DBG2(DBG_CFG, " mode = %N%s", ipsec_mode_names, cfg->mode, - cfg->proxy_mode ? "_PROXY" : ""); + cfg->options & OPT_PROXY_MODE ? "_PROXY" : ""); DBG2(DBG_CFG, " policies = %u", data->policies); - DBG2(DBG_CFG, " policies_fwd_out = %u", data->policies_fwd_out); + DBG2(DBG_CFG, " policies_fwd_out = %u", cfg->options & OPT_FWD_OUT_POLICIES); if (data->replay_window != REPLAY_UNDEFINED) { DBG2(DBG_CFG, " replay_window = %u", data->replay_window); @@ -525,6 +531,8 @@ static void log_child_data(child_data_t *data, char *name) DBG2(DBG_CFG, " proposals = %#P", data->proposals); DBG2(DBG_CFG, " local_ts = %#R", data->local_ts); DBG2(DBG_CFG, " remote_ts = %#R", data->remote_ts); + DBG2(DBG_CFG, " hw_offload = %u", cfg->options & OPT_HW_OFFLOAD); + DBG2(DBG_CFG, " sha256_96 = %u", cfg->options & OPT_SHA256_96); } /** @@ -827,13 +835,80 @@ CALLBACK(parse_mode, bool, if (parse_map(map, countof(map), &d, v)) { cfg->mode = d; - cfg->proxy_mode = (d == MODE_TRANSPORT) && (v.len > 9); + if ((d == MODE_TRANSPORT) && (v.len > 9)) + { + cfg->options |= OPT_PROXY_MODE; + } return TRUE; } return FALSE; } /** + * Enable a child_cfg_option_t + */ +static bool parse_option(child_cfg_option_t *out, child_cfg_option_t opt, + chunk_t v) +{ + bool val; + + if (parse_bool(&val, v)) + { + if (val) + { + *out |= opt; + } + return TRUE; + } + return FALSE; +} + +/** + * Parse OPT_HOSTACCESS option + */ +CALLBACK(parse_opt_haccess, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_HOSTACCESS, v); +} + +/** + * Parse OPT_FWD_OUT_POLICIES option + */ +CALLBACK(parse_opt_fwd_out, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_FWD_OUT_POLICIES, v); +} + +/** + * Parse OPT_FWD_OUT_POLICIES option + */ +CALLBACK(parse_opt_ipcomp, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_IPCOMP, v); +} + +/** + * Parse OPT_HW_OFFLOAD option + */ +CALLBACK(parse_opt_hw_offl, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_HW_OFFLOAD, v); +} + +/** + * Parse OPT_SHA256_96 option + */ +CALLBACK(parse_opt_sha256_96, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_SHA256_96, v); +} + +/** * Parse an action_t */ CALLBACK(parse_action, bool, @@ -1336,6 +1411,7 @@ CALLBACK(parse_frag, bool, { enum_map_t map[] = { { "yes", FRAGMENTATION_YES }, + { "accept", FRAGMENTATION_ACCEPT }, { "no", FRAGMENTATION_NO }, { "force", FRAGMENTATION_FORCE }, }; @@ -1465,10 +1541,10 @@ CALLBACK(child_kv, bool, { parse_rule_t rules[] = { { "updown", parse_string, &child->cfg.updown }, - { "hostaccess", parse_bool, &child->cfg.hostaccess }, + { "hostaccess", parse_opt_haccess, &child->cfg.options }, { "mode", parse_mode, &child->cfg }, { "policies", parse_bool, &child->policies }, - { "policies_fwd_out", parse_bool, &child->policies_fwd_out }, + { "policies_fwd_out", parse_opt_fwd_out, &child->cfg.options }, { "replay_window", parse_uint32, &child->replay_window }, { "rekey_time", parse_time, &child->cfg.lifetime.time.rekey }, { "life_time", parse_time, &child->cfg.lifetime.time.life }, @@ -1482,7 +1558,7 @@ CALLBACK(child_kv, bool, { "dpd_action", parse_action, &child->cfg.dpd_action }, { "start_action", parse_action, &child->cfg.start_action }, { "close_action", parse_action, &child->cfg.close_action }, - { "ipcomp", parse_bool, &child->cfg.ipcomp }, + { "ipcomp", parse_opt_ipcomp, &child->cfg.options }, { "inactivity", parse_time, &child->cfg.inactivity }, { "reqid", parse_uint32, &child->cfg.reqid }, { "mark_in", parse_mark, &child->cfg.mark_in }, @@ -1490,6 +1566,8 @@ CALLBACK(child_kv, bool, { "tfc_padding", parse_tfc, &child->cfg.tfc }, { "priority", parse_uint32, &child->cfg.priority }, { "interface", parse_string, &child->cfg.interface }, + { "hw_offload", parse_opt_hw_offl, &child->cfg.options }, + { "sha256_96", parse_opt_sha256_96,&child->cfg.options }, }; return parse_rules(rules, countof(rules), name, value, @@ -1755,8 +1833,7 @@ CALLBACK(children_sn, bool, child.proposals->insert_last(child.proposals, proposal); } } - child.cfg.suppress_policies = !child.policies; - child.cfg.fwd_out_policies = child.policies_fwd_out; + child.cfg.options |= child.policies ? 0 : OPT_NO_POLICIES; check_lifetimes(&child.cfg.lifetime); diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c index 6c7c194c2..5d8bf2f05 100644 --- a/src/libcharon/plugins/vici/vici_cred.c +++ b/src/libcharon/plugins/vici/vici_cred.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2015-2016 Andreas Steffen - * Copyright (C) 2016 Tobias Brunner + * Copyright (C) 2016-2017 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * Copyright (C) 2014 Martin Willi @@ -206,9 +206,10 @@ CALLBACK(load_cert, vici_message_t*, CALLBACK(load_key, vici_message_t*, private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) { + vici_builder_t *builder; key_type_t type; private_key_t *key; - chunk_t data; + chunk_t data, fp; char *str; str = message->get_str(message, NULL, "type"); @@ -248,12 +249,19 @@ CALLBACK(load_key, vici_message_t*, return create_reply("parsing %N private key failed", key_type_names, type); } + if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp)) + { + return create_reply("failed to get key id"); + } DBG1(DBG_CFG, "loaded %N private key", key_type_names, type); + builder = vici_builder_create(); + builder->add_kv(builder, "success", "yes"); + builder->add_kv(builder, "id", "%+B", &fp); this->creds->add_key(this->creds, key); - return create_reply(NULL); + return builder->finalize(builder); } CALLBACK(unload_key, vici_message_t*, diff --git a/src/libcharon/plugins/vici/vici_message.c b/src/libcharon/plugins/vici/vici_message.c index 58b896773..91d344994 100644 --- a/src/libcharon/plugins/vici/vici_message.c +++ b/src/libcharon/plugins/vici/vici_message.c @@ -135,11 +135,16 @@ typedef struct { } parse_enumerator_t; METHOD(enumerator_t, parse_enumerate, bool, - parse_enumerator_t *this, vici_type_t *out, char **name, chunk_t *value) + parse_enumerator_t *this, va_list args) { + vici_type_t *out; + chunk_t *value; + char **name; uint8_t type; chunk_t data; + VA_ARGS_VGET(args, out, name, value); + if (!this->reader->remaining(this->reader) || !this->reader->read_uint8(this->reader, &type)) { @@ -218,7 +223,8 @@ METHOD(vici_message_t, create_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_parse_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _parse_enumerate, .destroy = _parse_destroy, }, .reader = bio_reader_create(this->encoding), diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c index c0f4e2de9..2cc59591f 100644 --- a/src/libcharon/plugins/vici/vici_query.c +++ b/src/libcharon/plugins/vici/vici_query.c @@ -107,7 +107,7 @@ static void list_mode(vici_builder_t *b, child_sa_t *child, child_cfg_t *cfg) cfg = child->get_config(child); } mode = child ? child->get_mode(child) : cfg->get_mode(cfg); - if (mode == MODE_TRANSPORT && cfg->use_proxy_mode(cfg)) + if (mode == MODE_TRANSPORT && cfg->has_option(cfg, OPT_PROXY_MODE)) { /* only report this if the negotiated mode is actually TRANSPORT */ sub_mode = "_PROXY"; } diff --git a/src/libcharon/plugins/whitelist/Makefile.in b/src/libcharon/plugins/whitelist/Makefile.in index b85961387..0347c5f53 100644 --- a/src/libcharon/plugins/whitelist/Makefile.in +++ b/src/libcharon/plugins/whitelist/Makefile.in @@ -365,6 +365,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -387,6 +388,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/whitelist/whitelist_listener.c b/src/libcharon/plugins/whitelist/whitelist_listener.c index 7e5b2f4e0..136554674 100644 --- a/src/libcharon/plugins/whitelist/whitelist_listener.c +++ b/src/libcharon/plugins/whitelist/whitelist_listener.c @@ -119,14 +119,19 @@ METHOD(whitelist_listener_t, remove_, void, DESTROY_IF(id); } -/** - * Enumerator filter, from hashtable (key, value) to single identity - */ -static bool whitelist_filter(rwlock_t *lock, identification_t **key, - identification_t **id, identification_t **value) +CALLBACK(whitelist_filter, bool, + rwlock_t *lock, enumerator_t *orig, va_list args) { - *id = *value; - return TRUE; + identification_t *key, *value, **out; + + VA_ARGS_VGET(args, out); + + if (orig->enumerate(orig, &key, &value)) + { + *out = value; + return TRUE; + } + return FALSE; } METHOD(whitelist_listener_t, create_enumerator, enumerator_t*, @@ -134,7 +139,7 @@ METHOD(whitelist_listener_t, create_enumerator, enumerator_t*, { this->lock->read_lock(this->lock); return enumerator_create_filter(this->ids->create_enumerator(this->ids), - (void*)whitelist_filter, this->lock, + whitelist_filter, this->lock, (void*)this->lock->unlock); } diff --git a/src/libcharon/plugins/xauth_eap/Makefile.in b/src/libcharon/plugins/xauth_eap/Makefile.in index a6554d6a9..28158a373 100644 --- a/src/libcharon/plugins/xauth_eap/Makefile.in +++ b/src/libcharon/plugins/xauth_eap/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/xauth_generic/Makefile.in b/src/libcharon/plugins/xauth_generic/Makefile.in index 87d627bc3..1dc267545 100644 --- a/src/libcharon/plugins/xauth_generic/Makefile.in +++ b/src/libcharon/plugins/xauth_generic/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/xauth_noauth/Makefile.in b/src/libcharon/plugins/xauth_noauth/Makefile.in index 13fb71aef..a610bab2a 100644 --- a/src/libcharon/plugins/xauth_noauth/Makefile.in +++ b/src/libcharon/plugins/xauth_noauth/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/plugins/xauth_pam/Makefile.in b/src/libcharon/plugins/xauth_pam/Makefile.in index 821d46e6b..8c31f2472 100644 --- a/src/libcharon/plugins/xauth_pam/Makefile.in +++ b/src/libcharon/plugins/xauth_pam/Makefile.in @@ -358,6 +358,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.c b/src/libcharon/processing/jobs/delete_child_sa_job.c index 70dbc1b4a..048b879f1 100644 --- a/src/libcharon/processing/jobs/delete_child_sa_job.c +++ b/src/libcharon/processing/jobs/delete_child_sa_job.c @@ -1,6 +1,7 @@ /* + * Copyright (C) 2017 Tobias Brunner * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil + * HSR 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 @@ -24,19 +25,19 @@ typedef struct private_delete_child_sa_job_t private_delete_child_sa_job_t; * Private data of an delete_child_sa_job_t object. */ struct private_delete_child_sa_job_t { - /** + /** * Public delete_child_sa_job_t interface. */ delete_child_sa_job_t public; /** - * protocol of the CHILD_SA (ESP/AH) + * Protocol of the CHILD_SA (ESP/AH) */ protocol_id_t protocol; /** - * inbound SPI of the CHILD_SA + * Inbound SPI of the CHILD_SA */ uint32_t spi; @@ -49,12 +50,17 @@ struct private_delete_child_sa_job_t { * Delete for an expired CHILD_SA */ bool expired; + + /** + * Unique ID of the CHILD_SA + */ + uint32_t id; }; METHOD(job_t, destroy, void, private_delete_child_sa_job_t *this) { - this->dst->destroy(this->dst); + DESTROY_IF(this->dst); free(this); } @@ -63,17 +69,37 @@ METHOD(job_t, execute, job_requeue_t, { ike_sa_t *ike_sa; - ike_sa = charon->child_sa_manager->checkout(charon->child_sa_manager, - this->protocol, this->spi, this->dst, NULL); - if (ike_sa == NULL) + if (this->id) { - DBG1(DBG_JOB, "CHILD_SA %N/0x%08x/%H not found for delete", - protocol_id_names, this->protocol, htonl(this->spi), this->dst); + child_sa_t *child_sa; + + ike_sa = charon->child_sa_manager->checkout_by_id( + charon->child_sa_manager, this->id, &child_sa); + if (!ike_sa) + { + DBG1(DBG_JOB, "CHILD_SA {%d} not found for delete", this->id); + } + else + { + this->spi = child_sa->get_spi(child_sa, TRUE); + this->protocol = child_sa->get_protocol(child_sa); + } } else { - ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi, this->expired); + ike_sa = charon->child_sa_manager->checkout(charon->child_sa_manager, + this->protocol, this->spi, this->dst, NULL); + if (!ike_sa) + { + DBG1(DBG_JOB, "CHILD_SA %N/0x%08x/%H not found for delete", + protocol_id_names, this->protocol, htonl(this->spi), this->dst); + } + } + if (ike_sa) + { + ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi, + this->expired); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } return JOB_REQUEUE_NONE; @@ -109,3 +135,24 @@ delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol, return &this->public; } + +/* + * Described in header + */ +delete_child_sa_job_t *delete_child_sa_job_create_id(uint32_t id) +{ + private_delete_child_sa_job_t *this; + + INIT(this, + .public = { + .job_interface = { + .execute = _execute, + .get_priority = _get_priority, + .destroy = _destroy, + }, + }, + .id = id, + ); + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.h b/src/libcharon/processing/jobs/delete_child_sa_job.h index 349f5debb..b2d5a11f6 100644 --- a/src/libcharon/processing/jobs/delete_child_sa_job.h +++ b/src/libcharon/processing/jobs/delete_child_sa_job.h @@ -1,6 +1,7 @@ /* + * Copyright (C) 2017 Tobias Brunner * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil + * HSR 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 @@ -42,7 +43,7 @@ struct delete_child_sa_job_t { }; /** - * Creates a job of type DELETE_CHILD_SA. + * Creates a job that deletes a CHILD_SA. * * @param protocol protocol of the CHILD_SA * @param spi security parameter index of the CHILD_SA @@ -53,4 +54,12 @@ struct delete_child_sa_job_t { delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol, uint32_t spi, host_t *dst, bool expired); +/** + * Creates a job that deletes a CHILD_SA identified by its unique ID. + * + * @param id unique ID of the CHILD_SA + * @return delete_child_sa_job_t object + */ +delete_child_sa_job_t *delete_child_sa_job_create_id(uint32_t id); + #endif /** DELETE_CHILD_SA_JOB_H_ @}*/ diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index b9dd59b07..3d9f6133b 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -1,6 +1,6 @@ /* + * Copyright (C) 2006-2017 Tobias Brunner * Copyright (C) 2016 Andreas Steffen - * Copyright (C) 2006-2016 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -40,6 +40,12 @@ ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING, "DESTROYING", ); +ENUM(child_sa_outbound_state_names, CHILD_OUTBOUND_NONE, CHILD_OUTBOUND_INSTALLED, + "NONE", + "REGISTERED", + "INSTALLED", +); + typedef struct private_child_sa_t private_child_sa_t; /** @@ -92,6 +98,31 @@ struct private_child_sa_t { array_t *other_ts; /** + * Outbound encryption key cached during a rekeying + */ + chunk_t encr_r; + + /** + * Outbound integrity key cached during a rekeying + */ + chunk_t integ_r; + + /** + * Whether the outbound SA has only been registered yet during a rekeying + */ + child_sa_outbound_state_t outbound_state; + + /** + * Whether the peer supports TFCv3 + */ + bool tfcv3; + + /** + * The outbound SPI of the CHILD_SA that replaced this one during a rekeying + */ + uint32_t rekey_spi; + + /** * Protocol used to protect this SA, ESP|AH */ protocol_id_t protocol; @@ -265,6 +296,10 @@ METHOD(child_sa_t, get_config, child_cfg_t*, METHOD(child_sa_t, set_state, void, private_child_sa_t *this, child_sa_state_t state) { + DBG2(DBG_CHD, "CHILD_SA %s{%d} state change: %N => %N", + get_name(this), this->unique_id, + child_sa_state_names, this->state, + child_sa_state_names, state); charon->bus->child_state_change(charon->bus, &this->public, state); this->state = state; } @@ -275,6 +310,12 @@ METHOD(child_sa_t, get_state, child_sa_state_t, return this->state; } +METHOD(child_sa_t, get_outbound_state, child_sa_outbound_state_t, + private_child_sa_t *this) +{ + return this->outbound_state; +} + METHOD(child_sa_t, get_spi, uint32_t, private_child_sa_t *this, bool inbound) { @@ -394,10 +435,11 @@ struct policy_enumerator_t { }; METHOD(enumerator_t, policy_enumerate, bool, - policy_enumerator_t *this, traffic_selector_t **my_out, - traffic_selector_t **other_out) + policy_enumerator_t *this, va_list args) { - traffic_selector_t *other_ts; + traffic_selector_t *other_ts, **my_out, **other_out; + + VA_ARGS_VGET(args, my_out, other_out); while (this->ts || this->mine->enumerate(this->mine, &this->ts)) { @@ -446,7 +488,8 @@ METHOD(child_sa_t, create_policy_enumerator, enumerator_t*, INIT(e, .public = { - .enumerate = (void*)_policy_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _policy_enumerate, .destroy = _policy_destroy, }, .mine = array_create_enumerator(this->my_ts), @@ -504,7 +547,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) } else { - if (this->other_spi) + if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED) { kernel_ipsec_sa_id_t id = { .src = this->my_addr, @@ -691,14 +734,16 @@ METHOD(child_sa_t, alloc_cpi, uint16_t, return 0; } -METHOD(child_sa_t, install, status_t, - private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi, - uint16_t cpi, bool initiator, bool inbound, bool tfcv3, - linked_list_t *my_ts, linked_list_t *other_ts) +/** + * Install the given SA in the kernel + */ +static status_t install_internal(private_child_sa_t *this, chunk_t encr, + chunk_t integ, uint32_t spi, uint16_t cpi, bool initiator, bool inbound, + bool tfcv3) { uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size; uint16_t esn = NO_EXT_SEQ_NUMBERS; - linked_list_t *src_ts = NULL, *dst_ts = NULL; + linked_list_t *my_ts, *other_ts, *src_ts, *dst_ts; time_t now; kernel_ipsec_sa_id_t id; kernel_ipsec_add_sa_t sa; @@ -708,6 +753,12 @@ METHOD(child_sa_t, install, status_t, status_t status; bool update = FALSE; + /* BEET requires the bound address from the traffic selectors */ + my_ts = linked_list_create_from_enumerator( + array_create_enumerator(this->my_ts)); + other_ts = linked_list_create_from_enumerator( + array_create_enumerator(this->other_ts)); + /* now we have to decide which spi to use. Use self allocated, if "in", * or the one in the proposal, if not "in" (others). Additionally, * source and dest host switch depending on the role */ @@ -721,6 +772,8 @@ METHOD(child_sa_t, install, status_t, } this->my_spi = spi; this->my_cpi = cpi; + dst_ts = my_ts; + src_ts = other_ts; } else { @@ -728,11 +781,14 @@ METHOD(child_sa_t, install, status_t, dst = this->other_addr; this->other_spi = spi; this->other_cpi = cpi; + src_ts = my_ts; + dst_ts = other_ts; if (tfcv3) { tfc = this->config->get_tfc(this->config); } + this->outbound_state = CHILD_OUTBOUND_INSTALLED; } DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound", @@ -748,12 +804,22 @@ METHOD(child_sa_t, install, status_t, this->proposal->get_algorithm(this->proposal, EXTENDED_SEQUENCE_NUMBERS, &esn, NULL); + if (int_alg == AUTH_HMAC_SHA2_256_128 && + this->config->has_option(this->config, OPT_SHA256_96)) + { + DBG2(DBG_CHD, " using %N with 96-bit truncation", + integrity_algorithm_names, int_alg); + int_alg = AUTH_HMAC_SHA2_256_96; + } + if (!this->reqid_allocated && !this->static_reqid) { status = charon->kernel->alloc_reqid(charon->kernel, my_ts, other_ts, this->mark_in, this->mark_out, &this->reqid); if (status != SUCCESS) { + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); return status; } this->reqid_allocated = TRUE; @@ -783,18 +849,6 @@ METHOD(child_sa_t, install, status_t, lifetime->time.rekey = 0; } - /* BEET requires the bound address from the traffic selectors */ - if (inbound) - { - dst_ts = my_ts; - src_ts = other_ts; - } - else - { - src_ts = my_ts; - dst_ts = other_ts; - } - id = (kernel_ipsec_sa_id_t){ .src = src, .dst = dst, @@ -818,6 +872,7 @@ METHOD(child_sa_t, install, status_t, .ipcomp = this->ipcomp, .cpi = cpi, .encap = this->encap, + .hw_offload = this->config->has_option(this->config, OPT_HW_OFFLOAD), .esn = esn, .initiator = initiator, .inbound = inbound, @@ -826,11 +881,21 @@ METHOD(child_sa_t, install, status_t, status = charon->kernel->add_sa(charon->kernel, &id, &sa); + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); free(lifetime); return status; } +METHOD(child_sa_t, install, status_t, + private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi, + uint16_t cpi, bool initiator, bool inbound, bool tfcv3) +{ + return install_internal(this, encr, integ, spi, cpi, initiator, inbound, + tfcv3); +} + /** * Check kernel interface if policy updates are required */ @@ -887,34 +952,21 @@ static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa, } /** - * Install 3 policies: out, in and forward + * Install inbound policie(s): in, fwd */ -static status_t install_policies_internal(private_child_sa_t *this, +static status_t install_policies_inbound(private_child_sa_t *this, host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority, uint32_t manual_prio) { - kernel_ipsec_policy_id_t out_id = { - .dir = POLICY_OUT, - .src_ts = my_ts, - .dst_ts = other_ts, - .mark = this->mark_out, - .interface = this->config->get_interface(this->config), - }, in_id = { + kernel_ipsec_policy_id_t in_id = { .dir = POLICY_IN, .src_ts = other_ts, .dst_ts = my_ts, .mark = this->mark_in, }; - kernel_ipsec_manage_policy_t out_policy = { - .type = type, - .prio = priority, - .manual_prio = manual_prio, - .src = my_addr, - .dst = other_addr, - .sa = other_sa, - }, in_policy = { + kernel_ipsec_manage_policy_t in_policy = { .type = type, .prio = priority, .manual_prio = manual_prio, @@ -924,13 +976,45 @@ static status_t install_policies_internal(private_child_sa_t *this, }; status_t status = SUCCESS; - status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy); status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy); if (this->mode != MODE_TRANSPORT) { in_id.dir = POLICY_FWD; status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy); + } + return status; +} +/** + * Install outbound policie(s): out, [fwd] + */ +static status_t install_policies_outbound(private_child_sa_t *this, + host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, + traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, + ipsec_sa_cfg_t *other_sa, policy_type_t type, + policy_priority_t priority, uint32_t manual_prio) +{ + kernel_ipsec_policy_id_t out_id = { + .dir = POLICY_OUT, + .src_ts = my_ts, + .dst_ts = other_ts, + .mark = this->mark_out, + .interface = this->config->get_interface(this->config), + }; + kernel_ipsec_manage_policy_t out_policy = { + .type = type, + .prio = priority, + .manual_prio = manual_prio, + .src = my_addr, + .dst = other_addr, + .sa = other_sa, + }; + status_t status = SUCCESS; + + status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy); + + if (this->mode != MODE_TRANSPORT && this->policies_fwd_out) + { /* install an "outbound" FWD policy in case there is a drop policy * matching outbound forwarded traffic, to allow another tunnel to use * the reversed subnets and do the same we don't set a reqid (this also @@ -939,52 +1023,56 @@ static status_t install_policies_internal(private_child_sa_t *this, * policies of two SAs we install them with reduced priority. As they * basically act as bypass policies for drop policies we use a higher * priority than is used for them. */ - if (this->policies_fwd_out) + out_id.dir = POLICY_FWD; + other_sa->reqid = 0; + if (priority == POLICY_PRIORITY_DEFAULT) { - out_id.dir = POLICY_FWD; - other_sa->reqid = 0; - if (priority == POLICY_PRIORITY_DEFAULT) - { - out_policy.prio = POLICY_PRIORITY_ROUTED; - } - status |= charon->kernel->add_policy(charon->kernel, &out_id, - &out_policy); - /* reset the reqid for any other further policies */ - other_sa->reqid = this->reqid; + out_policy.prio = POLICY_PRIORITY_ROUTED; } + status |= charon->kernel->add_policy(charon->kernel, &out_id, + &out_policy); + /* reset the reqid for any other further policies */ + other_sa->reqid = this->reqid; } return status; } /** - * Delete 3 policies: out, in and forward + * Install all policies */ -static void del_policies_internal(private_child_sa_t *this, +static status_t install_policies_internal(private_child_sa_t *this, + host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, + traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, + ipsec_sa_cfg_t *other_sa, policy_type_t type, + policy_priority_t priority, uint32_t manual_prio) +{ + status_t status = SUCCESS; + + status |= install_policies_inbound(this, my_addr, other_addr, my_ts, + other_ts, my_sa, other_sa, type, + priority, manual_prio); + status |= install_policies_outbound(this, my_addr, other_addr, my_ts, + other_ts, my_sa, other_sa, type, + priority, manual_prio); + return status; +} + +/** + * Delete inbound policies: in, fwd + */ +static void del_policies_inbound(private_child_sa_t *this, host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority, uint32_t manual_prio) { - kernel_ipsec_policy_id_t out_id = { - .dir = POLICY_OUT, - .src_ts = my_ts, - .dst_ts = other_ts, - .mark = this->mark_out, - .interface = this->config->get_interface(this->config), - }, in_id = { + kernel_ipsec_policy_id_t in_id = { .dir = POLICY_IN, .src_ts = other_ts, .dst_ts = my_ts, .mark = this->mark_in, }; - kernel_ipsec_manage_policy_t out_policy = { - .type = type, - .prio = priority, - .manual_prio = manual_prio, - .src = my_addr, - .dst = other_addr, - .sa = other_sa, - }, in_policy = { + kernel_ipsec_manage_policy_t in_policy = { .type = type, .prio = priority, .manual_prio = manual_prio, @@ -993,49 +1081,83 @@ static void del_policies_internal(private_child_sa_t *this, .sa = my_sa, }; - charon->kernel->del_policy(charon->kernel, &out_id, &out_policy); charon->kernel->del_policy(charon->kernel, &in_id, &in_policy); + if (this->mode != MODE_TRANSPORT) { in_id.dir = POLICY_FWD; charon->kernel->del_policy(charon->kernel, &in_id, &in_policy); + } +} - if (this->policies_fwd_out) +/** + * Delete outbound policies: out, [fwd] + */ +static void del_policies_outbound(private_child_sa_t *this, + host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, + traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, + ipsec_sa_cfg_t *other_sa, policy_type_t type, + policy_priority_t priority, uint32_t manual_prio) +{ + kernel_ipsec_policy_id_t out_id = { + .dir = POLICY_OUT, + .src_ts = my_ts, + .dst_ts = other_ts, + .mark = this->mark_out, + .interface = this->config->get_interface(this->config), + }; + kernel_ipsec_manage_policy_t out_policy = { + .type = type, + .prio = priority, + .manual_prio = manual_prio, + .src = my_addr, + .dst = other_addr, + .sa = other_sa, + }; + + charon->kernel->del_policy(charon->kernel, &out_id, &out_policy); + + if (this->mode != MODE_TRANSPORT && this->policies_fwd_out) + { + out_id.dir = POLICY_FWD; + other_sa->reqid = 0; + if (priority == POLICY_PRIORITY_DEFAULT) { - out_id.dir = POLICY_FWD; - other_sa->reqid = 0; - if (priority == POLICY_PRIORITY_DEFAULT) - { - out_policy.prio = POLICY_PRIORITY_ROUTED; - } - charon->kernel->del_policy(charon->kernel, &out_id, &out_policy); - other_sa->reqid = this->reqid; + out_policy.prio = POLICY_PRIORITY_ROUTED; } + charon->kernel->del_policy(charon->kernel, &out_id, &out_policy); + other_sa->reqid = this->reqid; } } -METHOD(child_sa_t, add_policies, status_t, +/** + * Delete in- and outbound policies + */ +static void del_policies_internal(private_child_sa_t *this, + host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, + traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, + ipsec_sa_cfg_t *other_sa, policy_type_t type, + policy_priority_t priority, uint32_t manual_prio) +{ + del_policies_outbound(this, my_addr, other_addr, my_ts, other_ts, my_sa, + other_sa, type, priority, manual_prio); + del_policies_inbound(this, my_addr, other_addr, my_ts, other_ts, my_sa, + other_sa, type, priority, manual_prio); +} + +METHOD(child_sa_t, set_policies, void, private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list) { enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; - status_t status = SUCCESS; - if (!this->reqid_allocated && !this->static_reqid) + if (array_count(this->my_ts)) { - /* trap policy, get or confirm reqid */ - status = charon->kernel->alloc_reqid( - charon->kernel, my_ts_list, other_ts_list, - this->mark_in, this->mark_out, &this->reqid); - if (status != SUCCESS) - { - return status; - } - this->reqid_allocated = TRUE; + array_destroy_offset(this->my_ts, + offsetof(traffic_selector_t, destroy)); + this->my_ts = array_create(0, 0); } - - /* apply traffic selectors */ enumerator = my_ts_list->create_enumerator(my_ts_list); while (enumerator->enumerate(enumerator, &my_ts)) { @@ -1044,6 +1166,12 @@ METHOD(child_sa_t, add_policies, status_t, enumerator->destroy(enumerator); array_sort(this->my_ts, (void*)traffic_selector_cmp, NULL); + if (array_count(this->other_ts)) + { + array_destroy_offset(this->other_ts, + offsetof(traffic_selector_t, destroy)); + this->other_ts = array_create(0, 0); + } enumerator = other_ts_list->create_enumerator(other_ts_list); while (enumerator->enumerate(enumerator, &other_ts)) { @@ -1051,12 +1179,40 @@ METHOD(child_sa_t, add_policies, status_t, } enumerator->destroy(enumerator); array_sort(this->other_ts, (void*)traffic_selector_cmp, NULL); +} + +METHOD(child_sa_t, install_policies, status_t, + private_child_sa_t *this) +{ + enumerator_t *enumerator; + linked_list_t *my_ts_list, *other_ts_list; + traffic_selector_t *my_ts, *other_ts; + status_t status = SUCCESS; - if (this->config->install_policy(this->config)) + if (!this->reqid_allocated && !this->static_reqid) + { + my_ts_list = linked_list_create_from_enumerator( + array_create_enumerator(this->my_ts)); + other_ts_list = linked_list_create_from_enumerator( + array_create_enumerator(this->other_ts)); + status = charon->kernel->alloc_reqid( + charon->kernel, my_ts_list, other_ts_list, + this->mark_in, this->mark_out, &this->reqid); + my_ts_list->destroy(my_ts_list); + other_ts_list->destroy(other_ts_list); + if (status != SUCCESS) + { + return status; + } + this->reqid_allocated = TRUE; + } + + if (!this->config->has_option(this->config, OPT_NO_POLICIES)) { policy_priority_t priority; ipsec_sa_cfg_t my_sa, other_sa; uint32_t manual_prio; + bool install_outbound; prepare_sa_cfg(this, &my_sa, &other_sa); manual_prio = this->config->get_manual_prio(this->config); @@ -1066,6 +1222,7 @@ METHOD(child_sa_t, add_policies, status_t, this->trap = this->state == CHILD_CREATED; priority = this->trap ? POLICY_PRIORITY_ROUTED : POLICY_PRIORITY_DEFAULT; + install_outbound = this->outbound_state != CHILD_OUTBOUND_REGISTERED; /* enumerate pairs of traffic selectors */ enumerator = create_policy_enumerator(this); @@ -1074,20 +1231,27 @@ METHOD(child_sa_t, add_policies, status_t, /* install outbound drop policy to avoid packets leaving unencrypted * when updating policies */ if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 && - require_policy_update()) + require_policy_update() && install_outbound) { - status |= install_policies_internal(this, this->my_addr, + status |= install_policies_outbound(this, this->my_addr, this->other_addr, my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0); } - /* install policies */ - status |= install_policies_internal(this, this->my_addr, + status |= install_policies_inbound(this, this->my_addr, this->other_addr, my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC, priority, manual_prio); + if (install_outbound) + { + status |= install_policies_outbound(this, this->my_addr, + this->other_addr, my_ts, other_ts, + &my_sa, &other_sa, POLICY_IPSEC, + priority, manual_prio); + + } if (status != SUCCESS) { break; @@ -1103,13 +1267,150 @@ METHOD(child_sa_t, add_policies, status_t, return status; } -/** - * Callback to reinstall a virtual IP - */ -static void reinstall_vip(host_t *vip, host_t *me) +METHOD(child_sa_t, register_outbound, void, + private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi, + uint16_t cpi, bool tfcv3) +{ + DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names, + this->protocol); + DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr, + this->other_addr); + + this->other_spi = spi; + this->other_cpi = cpi; + this->encr_r = chunk_clone(encr); + this->integ_r = chunk_clone(integ); + this->tfcv3 = tfcv3; + this->outbound_state = CHILD_OUTBOUND_REGISTERED; +} + +METHOD(child_sa_t, install_outbound, status_t, + private_child_sa_t *this) +{ + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; + status_t status; + + status = install_internal(this, this->encr_r, this->integ_r, + this->other_spi, this->other_cpi, FALSE, FALSE, + this->tfcv3); + chunk_clear(&this->encr_r); + chunk_clear(&this->integ_r); + if (status != SUCCESS) + { + return status; + } + if (!this->config->has_option(this->config, OPT_NO_POLICIES)) + { + ipsec_sa_cfg_t my_sa, other_sa; + uint32_t manual_prio; + + prepare_sa_cfg(this, &my_sa, &other_sa); + manual_prio = this->config->get_manual_prio(this->config); + + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + /* install outbound drop policy to avoid packets leaving unencrypted + * when updating policies */ + if (manual_prio == 0 && require_policy_update()) + { + status |= install_policies_outbound(this, this->my_addr, + this->other_addr, my_ts, other_ts, + &my_sa, &other_sa, POLICY_DROP, + POLICY_PRIORITY_FALLBACK, 0); + } + status |= install_policies_outbound(this, this->my_addr, + this->other_addr, my_ts, other_ts, + &my_sa, &other_sa, POLICY_IPSEC, + POLICY_PRIORITY_DEFAULT, manual_prio); + if (status != SUCCESS) + { + break; + } + } + enumerator->destroy(enumerator); + } + return status; +} + +METHOD(child_sa_t, remove_outbound, void, + private_child_sa_t *this) +{ + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; + + switch (this->outbound_state) + { + case CHILD_OUTBOUND_INSTALLED: + break; + case CHILD_OUTBOUND_REGISTERED: + chunk_clear(&this->encr_r); + chunk_clear(&this->integ_r); + this->outbound_state = CHILD_OUTBOUND_NONE; + /* fall-through */ + case CHILD_OUTBOUND_NONE: + return; + } + + if (!this->config->has_option(this->config, OPT_NO_POLICIES)) + { + ipsec_sa_cfg_t my_sa, other_sa; + uint32_t manual_prio; + + prepare_sa_cfg(this, &my_sa, &other_sa); + manual_prio = this->config->get_manual_prio(this->config); + + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + del_policies_outbound(this, this->my_addr, this->other_addr, + my_ts, other_ts, &my_sa, &other_sa, + POLICY_IPSEC, POLICY_PRIORITY_DEFAULT, + manual_prio); + if (manual_prio == 0 && require_policy_update()) + { + del_policies_outbound(this, this->my_addr, this->other_addr, + my_ts, other_ts, &my_sa, &other_sa, + POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0); + } + } + enumerator->destroy(enumerator); + } + + kernel_ipsec_sa_id_t id = { + .src = this->my_addr, + .dst = this->other_addr, + .spi = this->other_spi, + .proto = proto_ike2ip(this->protocol), + .mark = this->mark_out, + }; + kernel_ipsec_del_sa_t sa = { + .cpi = this->other_cpi, + }; + charon->kernel->del_sa(charon->kernel, &id, &sa); + this->outbound_state = CHILD_OUTBOUND_NONE; +} + +METHOD(child_sa_t, set_rekey_spi, void, + private_child_sa_t *this, uint32_t spi) +{ + this->rekey_spi = spi; +} + +METHOD(child_sa_t, get_rekey_spi, uint32_t, + private_child_sa_t *this) { + return this->rekey_spi; +} + +CALLBACK(reinstall_vip, void, + host_t *vip, va_list args) +{ + host_t *me; char *iface; + VA_ARGS_VGET(args, me); if (charon->kernel->get_interface(charon->kernel, me, &iface)) { charon->kernel->del_ip(charon->kernel, vip, -1, TRUE); @@ -1134,8 +1435,9 @@ METHOD(child_sa_t, update, status_t, old = this->state; set_state(this, CHILD_UPDATING); - transport_proxy_mode = this->config->use_proxy_mode(this->config) && - this->mode == MODE_TRANSPORT; + transport_proxy_mode = this->mode == MODE_TRANSPORT && + this->config->has_option(this->config, + OPT_PROXY_MODE); if (!transport_proxy_mode) { @@ -1189,7 +1491,8 @@ METHOD(child_sa_t, update, status_t, } } - if (this->config->install_policy(this->config) && require_policy_update()) + if (!this->config->has_option(this->config, OPT_NO_POLICIES) && + require_policy_update()) { if (!me->ip_equals(me, this->my_addr) || !other->ip_equals(other, this->other_addr)) @@ -1229,7 +1532,7 @@ METHOD(child_sa_t, update, status_t, /* we reinstall the virtual IP to handle interface roaming * correctly */ - vips->invoke_function(vips, (void*)reinstall_vip, me); + vips->invoke_function(vips, reinstall_vip, me); /* reinstall updated policies */ install_policies_internal(this, me, other, my_ts, other_ts, @@ -1239,12 +1542,12 @@ METHOD(child_sa_t, update, status_t, /* update fallback policies after the new policy is in place */ if (manual_prio == 0) { - del_policies_internal(this, this->my_addr, this->other_addr, + del_policies_outbound(this, this->my_addr, this->other_addr, old_my_ts ?: my_ts, old_other_ts ?: other_ts, &my_sa, &other_sa, POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0); - install_policies_internal(this, me, other, my_ts, other_ts, + install_policies_outbound(this, me, other, my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0); } @@ -1287,25 +1590,35 @@ METHOD(child_sa_t, destroy, void, set_state(this, CHILD_DESTROYING); - if (this->config->install_policy(this->config)) + if (!this->config->has_option(this->config, OPT_NO_POLICIES)) { ipsec_sa_cfg_t my_sa, other_sa; uint32_t manual_prio; + bool del_outbound; prepare_sa_cfg(this, &my_sa, &other_sa); manual_prio = this->config->get_manual_prio(this->config); + del_outbound = this->trap || + this->outbound_state == CHILD_OUTBOUND_INSTALLED; /* delete all policies in the kernel */ enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - del_policies_internal(this, this->my_addr, this->other_addr, - my_ts, other_ts, &my_sa, &other_sa, - POLICY_IPSEC, priority, manual_prio); - if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 && - require_policy_update()) + if (del_outbound) { - del_policies_internal(this, this->my_addr, this->other_addr, + del_policies_outbound(this, this->my_addr, + this->other_addr, my_ts, other_ts, + &my_sa, &other_sa, POLICY_IPSEC, + priority, manual_prio); + } + del_policies_inbound(this, this->my_addr, this->other_addr, + my_ts, other_ts, &my_sa, &other_sa, + POLICY_IPSEC, priority, manual_prio); + if (!this->trap && manual_prio == 0 && require_policy_update() && + del_outbound) + { + del_policies_outbound(this, this->my_addr, this->other_addr, my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0); } @@ -1327,7 +1640,7 @@ METHOD(child_sa_t, destroy, void, }; charon->kernel->del_sa(charon->kernel, &id, &sa); } - if (this->other_spi) + if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED) { kernel_ipsec_sa_id_t id = { .src = this->my_addr, @@ -1357,6 +1670,8 @@ METHOD(child_sa_t, destroy, void, this->other_addr->destroy(this->other_addr); DESTROY_IF(this->proposal); this->config->destroy(this->config); + chunk_clear(&this->encr_r); + chunk_clear(&this->integ_r); free(this); } @@ -1414,6 +1729,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, .get_config = _get_config, .get_state = _get_state, .set_state = _set_state, + .get_outbound_state = _get_outbound_state, .get_spi = _get_spi, .get_cpi = _get_cpi, .get_protocol = _get_protocol, @@ -1436,8 +1752,14 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, .alloc_spi = _alloc_spi, .alloc_cpi = _alloc_cpi, .install = _install, + .register_outbound = _register_outbound, + .install_outbound = _install_outbound, + .remove_outbound = _remove_outbound, + .set_rekey_spi = _set_rekey_spi, + .get_rekey_spi = _get_rekey_spi, .update = _update, - .add_policies = _add_policies, + .set_policies = _set_policies, + .install_policies = _install_policies, .create_ts_enumerator = _create_ts_enumerator, .create_policy_enumerator = _create_policy_enumerator, .destroy = _destroy, @@ -1456,7 +1778,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, .mark_in = config->get_mark(config, TRUE), .mark_out = config->get_mark(config, FALSE), .install_time = time_monotonic(NULL), - .policies_fwd_out = config->install_fwd_out_policy(config), + .policies_fwd_out = config->has_option(config, OPT_FWD_OUT_POLICIES), ); this->config = config; @@ -1509,7 +1831,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */ if (config->get_mode(config) == MODE_TRANSPORT && - config->use_proxy_mode(config)) + config->has_option(config, OPT_PROXY_MODE)) { this->mode = MODE_TRANSPORT; diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index bc7df996a..b9a913da1 100644 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2006-2008 Tobias Brunner + * Copyright (C) 2006-2017 Tobias Brunner * Copyright (C) 2006-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger - * Hochschule fuer Technik Rapperswil + * HSR 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 @@ -24,6 +24,7 @@ #define CHILD_SA_H_ typedef enum child_sa_state_t child_sa_state_t; +typedef enum child_sa_outbound_state_t child_sa_outbound_state_t; typedef struct child_sa_t child_sa_t; #include <library.h> @@ -53,7 +54,7 @@ enum child_sa_state_t { CHILD_INSTALLING, /** - * Installed an in-use CHILD_SA + * Installed both SAs of a CHILD_SA */ CHILD_INSTALLED, @@ -94,6 +95,32 @@ enum child_sa_state_t { extern enum_name_t *child_sa_state_names; /** + * States of the outbound SA of a CHILD_SA + */ +enum child_sa_outbound_state_t { + + /** + * Outbound SA is not installed + */ + CHILD_OUTBOUND_NONE, + + /** + * Data for the outbound SA has been registered, but not installed yet + */ + CHILD_OUTBOUND_REGISTERED, + + /** + * The outbound SA is currently installed + */ + CHILD_OUTBOUND_INSTALLED, +}; + +/** + * enum strings for child_sa_outbound_state_t. + */ +extern enum_name_t *child_sa_outbound_state_names; + +/** * Represents an IPsec SAs between two hosts. * * A child_sa_t contains two SAs. SAs for both @@ -152,7 +179,14 @@ struct child_sa_t { * * @return CHILD_SA state */ - child_sa_state_t (*get_state) (child_sa_t *this); + child_sa_state_t (*get_state)(child_sa_t *this); + + /** + * Get the state of the outbound SA. + * + * @return outbound SA state + */ + child_sa_outbound_state_t (*get_outbound_state)(child_sa_t *this); /** * Set the state of the CHILD_SA. @@ -347,6 +381,8 @@ struct child_sa_t { /** * Install an IPsec SA for one direction. * + * set_policies() should be called before calling this. + * * @param encr encryption key, if any * @param integ integrity key * @param spi SPI to use, allocated for inbound @@ -354,26 +390,84 @@ struct child_sa_t { * @param initiator TRUE if initiator of exchange resulting in this SA * @param inbound TRUE to install an inbound SA, FALSE for outbound * @param tfcv3 TRUE if peer supports ESPv3 TFC - * @param my_ts negotiated local traffic selector list - * @param other_ts negotiated remote traffic selector list * @return SUCCESS or FAILED */ status_t (*install)(child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi, uint16_t cpi, - bool initiator, bool inbound, bool tfcv3, - linked_list_t *my_ts, linked_list_t *other_ts); + bool initiator, bool inbound, bool tfcv3); + + /** + * Register data for the installation of an outbound SA as responder during + * a rekeying. + * + * The SA is not installed until install_outbound() is called. + * + * @param encr encryption key, if any (cloned) + * @param integ integrity key (cloned) + * @param spi SPI to use, allocated for inbound + * @param cpi CPI to use, allocated for outbound + * @param tfcv3 TRUE if peer supports ESPv3 TFC + */ + void (*register_outbound)(child_sa_t *this, chunk_t encr, chunk_t integ, + uint32_t spi, uint16_t cpi, bool tfcv3); + + /** + * Install the outbound SA and the outbound policies as responder during a + * rekeying. + * + * @return SUCCESS or FAILED + */ + status_t (*install_outbound)(child_sa_t *this); + + /** + * Remove the outbound SA and the outbound policies after a rekeying. + */ + void (*remove_outbound)(child_sa_t *this); + /** - * Install the policies using some traffic selectors. + * Configure the policies using some traffic selectors. * * Supplied lists of traffic_selector_t's specify the policies * to use for this child sa. * - * @param my_ts traffic selectors for local site - * @param other_ts traffic selectors for remote site + * Install the policies by calling install_policies(). + * + * This should be called before calling install() so the traffic selectors + * may be passed to the kernel interface when installing the SAs. + * + * @param my_ts traffic selectors for local site (cloned) + * @param other_ts traffic selectors for remote site (cloned) + */ + void (*set_policies)(child_sa_t *this, linked_list_t *my_ts_list, + linked_list_t *other_ts_list); + + /** + * Install the configured policies. + * + * If register_outbound() was called previously this only installs the + * inbound and forward policies, the outbound policies are installed when + * install_outbound() is called. + * * @return SUCCESS or FAILED */ - status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list, - linked_list_t *other_ts_list); + status_t (*install_policies)(child_sa_t *this); + + /** + * Set the outbound SPI of the CHILD_SA that replaced this CHILD_SA during + * a rekeying. + * + * @param spi outbound SPI of the CHILD_SA that replaced this CHILD_SA + */ + void (*set_rekey_spi)(child_sa_t *this, uint32_t spi); + + /** + * Get the outbound SPI of the CHILD_SA that replaced this CHILD_SA during + * a rekeying. + * + * @return outbound SPI of the CHILD_SA that replaced this CHILD_SA + */ + uint32_t (*get_rekey_spi)(child_sa_t *this); + /** * Update hosts and ecapulation mode in the kernel SAs and policies. * diff --git a/src/libcharon/sa/eap/eap_manager.c b/src/libcharon/sa/eap/eap_manager.c index e4fcbc8f0..b2a57ccfb 100644 --- a/src/libcharon/sa/eap/eap_manager.c +++ b/src/libcharon/sa/eap/eap_manager.c @@ -105,31 +105,38 @@ METHOD(eap_manager_t, remove_method, void, this->lock->unlock(this->lock); } -/** - * filter the registered methods - */ -static bool filter_methods(uintptr_t role, eap_entry_t **entry, - eap_type_t *type, void *in, uint32_t *vendor) +CALLBACK(filter_methods, bool, + uintptr_t role, enumerator_t *orig, va_list args) { - if ((*entry)->role != (eap_role_t)role) - { - return FALSE; - } - if ((*entry)->vendor == 0 && - ((*entry)->type < 4 || (*entry)->type == EAP_EXPANDED || - (*entry)->type > EAP_EXPERIMENTAL)) - { /* filter invalid types */ - return FALSE; - } - if (type) - { - *type = (*entry)->type; - } - if (vendor) + eap_entry_t *entry; + eap_type_t *type; + uint32_t *vendor; + + VA_ARGS_VGET(args, type, vendor); + + while (orig->enumerate(orig, &entry)) { - *vendor = (*entry)->vendor; + if (entry->role != (eap_role_t)role) + { + continue; + } + if (entry->vendor == 0 && + (entry->type < 4 || entry->type == EAP_EXPANDED || + entry->type > EAP_EXPERIMENTAL)) + { /* filter invalid types */ + continue; + } + if (type) + { + *type = entry->type; + } + if (vendor) + { + *vendor = entry->vendor; + } + return TRUE; } - return TRUE; + return FALSE; } METHOD(eap_manager_t, create_enumerator, enumerator_t*, @@ -139,7 +146,7 @@ METHOD(eap_manager_t, create_enumerator, enumerator_t*, return enumerator_create_cleaner( enumerator_create_filter( this->methods->create_enumerator(this->methods), - (void*)filter_methods, (void*)(uintptr_t)role, NULL), + filter_methods, (void*)(uintptr_t)role, NULL), (void*)this->lock->unlock, this->lock); } diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 76e10691f..045858792 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1200,12 +1200,20 @@ METHOD(ike_sa_t, generate_message, status_t, return status; } -static bool filter_fragments(private_ike_sa_t *this, packet_t **fragment, - packet_t **packet) +CALLBACK(filter_fragments, bool, + private_ike_sa_t *this, enumerator_t *orig, va_list args) { - *packet = (*fragment)->clone(*fragment); - set_dscp(this, *packet); - return TRUE; + packet_t *fragment, **packet; + + VA_ARGS_VGET(args, packet); + + if (orig->enumerate(orig, &fragment)) + { + *packet = fragment->clone(fragment); + set_dscp(this, *packet); + return TRUE; + } + return FALSE; } METHOD(ike_sa_t, generate_message_fragmented, status_t, @@ -1265,7 +1273,7 @@ METHOD(ike_sa_t, generate_message_fragmented, status_t, { charon->bus->message(charon->bus, message, FALSE, FALSE); } - *packets = enumerator_create_filter(fragments, (void*)filter_fragments, + *packets = enumerator_create_filter(fragments, filter_fragments, this, NULL); } return status; @@ -1699,8 +1707,11 @@ typedef struct { } child_enumerator_t; METHOD(enumerator_t, child_enumerate, bool, - child_enumerator_t *this, child_sa_t **child_sa) + child_enumerator_t *this, va_list args) { + child_sa_t **child_sa; + + VA_ARGS_VGET(args, child_sa); if (this->inner->enumerate(this->inner, &this->current)) { *child_sa = this->current; @@ -1723,7 +1734,8 @@ METHOD(ike_sa_t, create_child_sa_enumerator, enumerator_t*, INIT(enumerator, .public = { - .enumerate = (void*)_child_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _child_enumerate, .destroy = _child_enumerator_destroy, }, .inner = array_create_enumerator(this->child_sas), @@ -2619,24 +2631,31 @@ METHOD(ike_sa_t, add_configuration_attribute, void, array_insert(this->attributes, ARRAY_TAIL, &entry); } -/** - * Enumerator filter for attributes - */ -static bool filter_attribute(void *null, attribute_entry_t **in, - configuration_attribute_type_t *type, void *in2, - chunk_t *data, void *in3, bool *handled) +CALLBACK(filter_attribute, bool, + void *null, enumerator_t *orig, va_list args) { - *type = (*in)->type; - *data = (*in)->data; - *handled = (*in)->handler != NULL; - return TRUE; + attribute_entry_t *entry; + configuration_attribute_type_t *type; + chunk_t *data; + bool *handled; + + VA_ARGS_VGET(args, type, data, handled); + + if (orig->enumerate(orig, &entry)) + { + *type = entry->type; + *data = entry->data; + *handled = entry->handler != NULL; + return TRUE; + } + return FALSE; } METHOD(ike_sa_t, create_attribute_enumerator, enumerator_t*, private_ike_sa_t *this) { return enumerator_create_filter(array_create_enumerator(this->attributes), - (void*)filter_attribute, NULL, NULL); + filter_attribute, NULL, NULL); } METHOD(ike_sa_t, create_task_enumerator, enumerator_t*, diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 6bd49a086..c0bfebb83 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -151,8 +151,10 @@ static entry_t *entry_create() /** * Function that matches entry_t objects by ike_sa_id_t. */ -static bool entry_match_by_id(entry_t *entry, ike_sa_id_t *id) +static bool entry_match_by_id(entry_t *entry, void *arg) { + ike_sa_id_t *id = arg; + if (id->equals(id, entry->ike_sa_id)) { return TRUE; @@ -172,7 +174,7 @@ static bool entry_match_by_id(entry_t *entry, ike_sa_id_t *id) /** * Function that matches entry_t objects by ike_sa_t pointers. */ -static bool entry_match_by_sa(entry_t *entry, ike_sa_t *ike_sa) +static bool entry_match_by_sa(entry_t *entry, void *ike_sa) { return entry->ike_sa == ike_sa; } @@ -276,9 +278,6 @@ typedef struct segment_t segment_t; struct segment_t { /** mutex to access a segment exclusively */ mutex_t *mutex; - - /** the number of entries in this segment */ - u_int count; }; typedef struct shareable_segment_t shareable_segment_t; @@ -371,6 +370,11 @@ struct private_ike_sa_manager_t { refcount_t half_open_count_responder; /** + * Total number of IKE_SAs registered with IKE_SA manager. + */ + refcount_t total_sa_count; + + /** * Hash table with connected_peers_t objects. */ table_item_t **connected_peers_table; @@ -511,8 +515,13 @@ struct private_enumerator_t { }; METHOD(enumerator_t, enumerate, bool, - private_enumerator_t *this, entry_t **entry, u_int *segment) + private_enumerator_t *this, va_list args) { + entry_t **entry; + u_int *segment; + + VA_ARGS_VGET(args, entry, segment); + if (this->entry) { this->entry->condvar->signal(this->entry->condvar); @@ -570,7 +579,8 @@ static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this) INIT(enumerator, .enumerator = { - .enumerate = (void*)_enumerate, + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate, .destroy = _enumerator_destroy, }, .manager = this, @@ -601,7 +611,7 @@ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry) item->next = current; } this->ike_sa_table[row] = item; - this->segments[segment].count++; + ref_get(&this->total_sa_count); return segment; } @@ -612,10 +622,9 @@ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry) static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry) { table_item_t *item, *prev = NULL; - u_int row, segment; + u_int row; row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; - segment = row & this->segment_mask; item = this->ike_sa_table[row]; while (item) { @@ -629,7 +638,7 @@ static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry) { this->ike_sa_table[row] = item->next; } - this->segments[segment].count--; + ignore_result(ref_put(&this->total_sa_count)); free(item); break; } @@ -648,7 +657,7 @@ static void remove_entry_at(private_enumerator_t *this) { table_item_t *current = this->current; - this->manager->segments[this->segment].count--; + ignore_result(ref_put(&this->manager->total_sa_count)); this->current = this->prev; if (this->prev) @@ -670,7 +679,7 @@ static void remove_entry_at(private_enumerator_t *this) */ static status_t get_entry_by_match_function(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment, - linked_list_match_t match, void *param) + bool (*match)(entry_t*,void*), void *param) { table_item_t *item; u_int row, seg; @@ -703,7 +712,7 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment) { return get_entry_by_match_function(this, ike_sa_id, entry, segment, - (linked_list_match_t)entry_match_by_id, ike_sa_id); + entry_match_by_id, ike_sa_id); } /** @@ -714,7 +723,7 @@ static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_t *ike_sa, entry_t **entry, u_int *segment) { return get_entry_by_match_function(this, ike_sa_id, entry, segment, - (linked_list_match_t)entry_match_by_sa, ike_sa); + entry_match_by_sa, ike_sa); } /** @@ -851,6 +860,15 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry) lock->unlock(lock); } +CALLBACK(id_matches, bool, + ike_sa_id_t *a, va_list args) +{ + ike_sa_id_t *b; + + VA_ARGS_VGET(args, b); + return a->equals(a, b); +} + /** * Put an SA between two peers into the hash table. */ @@ -879,8 +897,7 @@ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) entry->other_id, family)) { if (connected_peers->sas->find_first(connected_peers->sas, - (linked_list_match_t)entry->ike_sa_id->equals, - NULL, entry->ike_sa_id) == SUCCESS) + id_matches, NULL, entry->ike_sa_id)) { lock->unlock(lock); return; @@ -1555,42 +1572,52 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*, return ike_sa; } -/** - * enumerator filter function, waiting variant - */ -static bool enumerator_filter_wait(private_ike_sa_manager_t *this, - entry_t **in, ike_sa_t **out, u_int *segment) +CALLBACK(enumerator_filter_wait, bool, + private_ike_sa_manager_t *this, enumerator_t *orig, va_list args) { - if (wait_for_entry(this, *in, *segment)) + entry_t *entry; + u_int segment; + ike_sa_t **out; + + VA_ARGS_VGET(args, out); + + while (orig->enumerate(orig, &entry, &segment)) { - *out = (*in)->ike_sa; - charon->bus->set_sa(charon->bus, *out); - return TRUE; + if (wait_for_entry(this, entry, segment)) + { + *out = entry->ike_sa; + charon->bus->set_sa(charon->bus, *out); + return TRUE; + } } return FALSE; } -/** - * enumerator filter function, skipping variant - */ -static bool enumerator_filter_skip(private_ike_sa_manager_t *this, - entry_t **in, ike_sa_t **out, u_int *segment) +CALLBACK(enumerator_filter_skip, bool, + private_ike_sa_manager_t *this, enumerator_t *orig, va_list args) { - if (!(*in)->driveout_new_threads && - !(*in)->driveout_waiting_threads && - !(*in)->checked_out) + entry_t *entry; + u_int segment; + ike_sa_t **out; + + VA_ARGS_VGET(args, out); + + while (orig->enumerate(orig, &entry, &segment)) { - *out = (*in)->ike_sa; - charon->bus->set_sa(charon->bus, *out); - return TRUE; + if (!entry->driveout_new_threads && + !entry->driveout_waiting_threads && + !entry->checked_out) + { + *out = entry->ike_sa; + charon->bus->set_sa(charon->bus, *out); + return TRUE; + } } return FALSE; } -/** - * Reset threads SA after enumeration - */ -static void reset_sa(void *data) +CALLBACK(reset_sa, void, + void *data) { charon->bus->set_sa(charon->bus, NULL); } @@ -2034,17 +2061,7 @@ METHOD(ike_sa_manager_t, has_contact, bool, METHOD(ike_sa_manager_t, get_count, u_int, private_ike_sa_manager_t *this) { - u_int segment, count = 0; - mutex_t *mutex; - - for (segment = 0; segment < this->segment_count; segment++) - { - mutex = this->segments[segment & this->segment_mask].mutex; - mutex->lock(mutex); - count += this->segments[segment].count; - mutex->unlock(mutex); - } - return count; + return (u_int)ref_cur(&this->total_sa_count); } METHOD(ike_sa_manager_t, get_half_open_count, u_int, diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 1da17ee50..48ec3e7f5 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -210,6 +210,16 @@ struct private_task_manager_t { double retransmit_base; /** + * Jitter to apply to calculated retransmit timeout (in percent) + */ + u_int retransmit_jitter; + + /** + * Limit retransmit timeout to this value + */ + uint32_t retransmit_limit; + + /** * Sequence number for sending DPD requests */ uint32_t dpd_send; @@ -345,7 +355,7 @@ static status_t retransmit_packet(private_task_manager_t *this, uint32_t seqnr, u_int mid, u_int retransmitted, array_t *packets) { packet_t *packet; - uint32_t t; + uint32_t t, max_jitter; array_get(packets, 0, &packet); if (retransmitted > this->retransmit_tries) @@ -356,6 +366,15 @@ static status_t retransmit_packet(private_task_manager_t *this, uint32_t seqnr, } t = (uint32_t)(this->retransmit_timeout * 1000.0 * pow(this->retransmit_base, retransmitted)); + if (this->retransmit_limit) + { + t = min(t, this->retransmit_limit); + } + if (this->retransmit_jitter) + { + max_jitter = (t / 100.0) * this->retransmit_jitter; + t -= max_jitter * (random() / (RAND_MAX + 1.0)); + } if (retransmitted) { DBG1(DBG_IKE, "sending retransmit %u of %s message ID %u, seq %u", @@ -2034,11 +2053,15 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .active_tasks = linked_list_create(), .passive_tasks = linked_list_create(), .retransmit_tries = lib->settings->get_int(lib->settings, - "%s.retransmit_tries", RETRANSMIT_TRIES, lib->ns), + "%s.retransmit_tries", RETRANSMIT_TRIES, lib->ns), .retransmit_timeout = lib->settings->get_double(lib->settings, - "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns), + "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns), .retransmit_base = lib->settings->get_double(lib->settings, - "%s.retransmit_base", RETRANSMIT_BASE, lib->ns), + "%s.retransmit_base", RETRANSMIT_BASE, lib->ns), + .retransmit_jitter = min(lib->settings->get_int(lib->settings, + "%s.retransmit_jitter", 0, lib->ns), RETRANSMIT_JITTER_MAX), + .retransmit_limit = lib->settings->get_int(lib->settings, + "%s.retransmit_limit", 0, lib->ns) * 1000, ); if (!this->rng) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index bbb885850..8be82ebe2 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -325,6 +325,17 @@ static bool install(private_quick_mode_t *this) return FALSE; } + if (this->initiator) + { + this->child_sa->set_policies(this->child_sa, tsi, tsr); + } + else + { + this->child_sa->set_policies(this->child_sa, tsr, tsi); + } + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh, this->spi_i, this->spi_r, this->nonce_i, this->nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) @@ -333,19 +344,19 @@ static bool install(private_quick_mode_t *this) { status_i = this->child_sa->install(this->child_sa, encr_r, integ_r, this->spi_i, this->cpi_i, - this->initiator, TRUE, FALSE, tsi, tsr); + this->initiator, TRUE, FALSE); status_o = this->child_sa->install(this->child_sa, encr_i, integ_i, this->spi_r, this->cpi_r, - this->initiator, FALSE, FALSE, tsi, tsr); + this->initiator, FALSE, FALSE); } else { status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, this->spi_r, this->cpi_r, - this->initiator, TRUE, FALSE, tsr, tsi); + this->initiator, TRUE, FALSE); status_o = this->child_sa->install(this->child_sa, encr_r, integ_r, this->spi_i, this->cpi_i, - this->initiator, FALSE, FALSE, tsr, tsi); + this->initiator, FALSE, FALSE); } } @@ -355,22 +366,12 @@ static bool install(private_quick_mode_t *this) (status_i != SUCCESS) ? "inbound " : "", (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "", (status_o != SUCCESS) ? "outbound " : ""); - tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); - tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); status = FAILED; } else { - if (this->initiator) - { - status = this->child_sa->add_policies(this->child_sa, tsi, tsr); - } - else - { - status = this->child_sa->add_policies(this->child_sa, tsr, tsi); - } - tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); - tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + status = this->child_sa->install_policies(this->child_sa); + if (status != SUCCESS) { DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); @@ -853,7 +854,7 @@ METHOD(task_t, build_i, status_t, add_nat_oa_payloads(this, message); } - if (this->config->use_ipcomp(this->config)) + if (this->config->has_option(this->config, OPT_IPCOMP)) { this->cpi_i = this->child_sa->alloc_cpi(this->child_sa); if (!this->cpi_i) @@ -1108,7 +1109,7 @@ METHOD(task_t, process_r, status_t, return send_notify(this, INVALID_ID_INFORMATION); } - if (this->config->use_ipcomp(this->config)) + if (this->config->has_option(this->config, OPT_IPCOMP)) { list = sa_payload->get_ipcomp_proposals(sa_payload, &this->cpi_i); diff --git a/src/libcharon/sa/ikev2/connect_manager.c b/src/libcharon/sa/ikev2/connect_manager.c index 280796d8c..35856788c 100644 --- a/src/libcharon/sa/ikev2/connect_manager.c +++ b/src/libcharon/sa/ikev2/connect_manager.c @@ -450,22 +450,21 @@ static initiate_data_t *initiate_data_create(check_list_t *checklist, return this; } -/** - * Find an initiated connection by the peers' ids - */ -static bool match_initiated_by_ids(initiated_t *current, identification_t *id, - identification_t *peer_id) +CALLBACK(match_initiated_by_ids, bool, + initiated_t *current, va_list args) { + identification_t *id, *peer_id; + + VA_ARGS_VGET(args, id, peer_id); return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id); } -static status_t get_initiated_by_ids(private_connect_manager_t *this, - identification_t *id, - identification_t *peer_id, - initiated_t **initiated) +static bool get_initiated_by_ids(private_connect_manager_t *this, + identification_t *id, + identification_t *peer_id, + initiated_t **initiated) { - return this->initiated->find_first(this->initiated, - (linked_list_match_t)match_initiated_by_ids, + return this->initiated->find_first(this->initiated, match_initiated_by_ids, (void**)initiated, id, peer_id); } @@ -490,21 +489,20 @@ static void remove_initiated(private_connect_manager_t *this, enumerator->destroy(enumerator); } -/** - * Find the checklist with a specific connect ID - */ -static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id) +CALLBACK(match_checklist_by_id, bool, + check_list_t *current, va_list args) { - return chunk_equals(*connect_id, current->connect_id); + chunk_t connect_id; + + VA_ARGS_VGET(args, connect_id); + return chunk_equals(connect_id, current->connect_id); } -static status_t get_checklist_by_id(private_connect_manager_t *this, - chunk_t connect_id, - check_list_t **check_list) +static bool get_checklist_by_id(private_connect_manager_t *this, + chunk_t connect_id, check_list_t **check_list) { - return this->checklists->find_first(this->checklists, - (linked_list_match_t)match_checklist_by_id, - (void**)check_list, &connect_id); + return this->checklists->find_first(this->checklists, match_checklist_by_id, + (void**)check_list, connect_id); } /** @@ -528,19 +526,19 @@ static void remove_checklist(private_connect_manager_t *this, enumerator->destroy(enumerator); } -/** - * Checks if a list of endpoint_notify_t contains a certain host_t - */ -static bool match_endpoint_by_host(endpoint_notify_t *current, host_t *host) +CALLBACK(match_endpoint_by_host, bool, + endpoint_notify_t *current, va_list args) { + host_t *host; + + VA_ARGS_VGET(args, host); return host->equals(host, current->get_host(current)); } -static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, +static bool endpoints_contain(linked_list_t *endpoints, host_t *host, endpoint_notify_t **endpoint) { - return endpoints->find_first(endpoints, - (linked_list_match_t)match_endpoint_by_host, + return endpoints->find_first(endpoints, match_endpoint_by_host, (void**)endpoint, host); } @@ -560,39 +558,44 @@ static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair) enumerator->destroy(enumerator); } -/** - * Searches a list of endpoint_pair_t for a pair with specific host_ts - */ -static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local, - host_t *remote) +CALLBACK(match_pair_by_hosts, bool, + endpoint_pair_t *current, va_list args) { - return local->equals(local, current->local) && remote->equals(remote, current->remote); + host_t *local, *remote; + + VA_ARGS_VGET(args, local, remote); + return local->equals(local, current->local) && + remote->equals(remote, current->remote); } -static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, - host_t *remote, endpoint_pair_t **pair) +static bool get_pair_by_hosts(linked_list_t *pairs, host_t *local, + host_t *remote, endpoint_pair_t **pair) { - return pairs->find_first(pairs, (linked_list_match_t)match_pair_by_hosts, - (void**)pair, local, remote); + return pairs->find_first(pairs, match_pair_by_hosts, (void**)pair, local, + remote); } -static bool match_pair_by_id(endpoint_pair_t *current, uint32_t *id) +CALLBACK(match_pair_by_id, bool, + endpoint_pair_t *current, va_list args) { - return current->id == *id; + uint32_t id; + + VA_ARGS_VGET(args, id); + return current->id == id; } /** * Searches for a pair with a specific id */ -static status_t get_pair_by_id(check_list_t *checklist, uint32_t id, - endpoint_pair_t **pair) +static bool get_pair_by_id(check_list_t *checklist, uint32_t id, + endpoint_pair_t **pair) { - return checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_pair_by_id, - (void**)pair, &id); + return checklist->pairs->find_first(checklist->pairs, match_pair_by_id, + (void**)pair, id); } -static bool match_succeeded_pair(endpoint_pair_t *current) +CALLBACK(match_succeeded_pair, bool, + endpoint_pair_t *current, va_list args) { return current->state == CHECK_SUCCEEDED; } @@ -600,15 +603,14 @@ static bool match_succeeded_pair(endpoint_pair_t *current) /** * Returns the best pair of state CHECK_SUCCEEDED from a checklist. */ -static status_t get_best_valid_pair(check_list_t *checklist, - endpoint_pair_t **pair) +static bool get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **pair) { - return checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_succeeded_pair, - (void**)pair); + return checklist->pairs->find_first(checklist->pairs, match_succeeded_pair, + (void**)pair); } -static bool match_waiting_pair(endpoint_pair_t *current) +CALLBACK(match_waiting_pair, bool, + endpoint_pair_t *current, va_list args) { return current->state == CHECK_WAITING; } @@ -865,7 +867,7 @@ static job_requeue_t initiator_finish(callback_data_t *data) this->mutex->lock(this->mutex); check_list_t *checklist; - if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) + if (!get_checklist_by_id(this, data->connect_id, &checklist)) { DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish " "connectivity checks", &data->connect_id); @@ -953,7 +955,7 @@ static job_requeue_t retransmit(callback_data_t *data) this->mutex->lock(this->mutex); check_list_t *checklist; - if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) + if (!get_checklist_by_id(this, data->connect_id, &checklist)) { DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit " "connectivity check", &data->connect_id); @@ -962,7 +964,7 @@ static job_requeue_t retransmit(callback_data_t *data) } endpoint_pair_t *pair; - if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS) + if (!get_pair_by_id(checklist, data->mid, &pair)) { DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit " "connectivity check", data->mid); @@ -1108,7 +1110,7 @@ static job_requeue_t sender(callback_data_t *data) this->mutex->lock(this->mutex); check_list_t *checklist; - if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) + if (!get_checklist_by_id(this, data->connect_id, &checklist)) { DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send " "connectivity check", &data->connect_id); @@ -1124,9 +1126,8 @@ static job_requeue_t sender(callback_data_t *data) { DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check"); - if (checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_waiting_pair, - (void**)&pair) != SUCCESS) + if (!checklist->pairs->find_first(checklist->pairs, match_waiting_pair, + (void**)&pair)) { this->mutex->unlock(this->mutex); DBG1(DBG_IKE, "no pairs in waiting state, aborting"); @@ -1182,7 +1183,7 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) initiated_t *initiated = data->initiated; endpoint_pair_t *pair; - if (get_best_valid_pair(checklist, &pair) == SUCCESS) + if (get_best_valid_pair(checklist, &pair)) { ike_sa_id_t *waiting_sa; enumerator_t *enumerator = initiated->mediated->create_enumerator( @@ -1219,7 +1220,7 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli { initiated_t *initiated; if (get_initiated_by_ids(this, checklist->initiator.id, - checklist->responder.id, &initiated) == SUCCESS) + checklist->responder.id, &initiated)) { callback_job_t *job; @@ -1247,7 +1248,7 @@ static void process_response(private_connect_manager_t *this, check_t *check, check_list_t *checklist) { endpoint_pair_t *pair; - if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS) + if (get_pair_by_id(checklist, check->mid, &pair)) { if (pair->local->equals(pair->local, check->dst) && pair->remote->equals(pair->remote, check->src)) @@ -1261,9 +1262,9 @@ static void process_response(private_connect_manager_t *this, check_t *check, checklist->initiator.endpoints : checklist->responder.endpoints; endpoint_notify_t *local_endpoint; - if (endpoints_contain(local_endpoints, - check->endpoint->get_host(check->endpoint), - &local_endpoint) != SUCCESS) + if (!endpoints_contain(local_endpoints, + check->endpoint->get_host(check->endpoint), + &local_endpoint)) { local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, check->endpoint->get_host(check->endpoint), pair->local); @@ -1302,15 +1303,14 @@ static void process_request(private_connect_manager_t *this, check_t *check, peer_reflexive->set_priority(peer_reflexive, check->endpoint->get_priority(check->endpoint)); - if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS) + if (!endpoints_contain(remote_endpoints, check->src, &remote_endpoint)) { remote_endpoint = peer_reflexive->clone(peer_reflexive); remote_endpoints->insert_last(remote_endpoints, remote_endpoint); } endpoint_pair_t *pair; - if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, - &pair) == SUCCESS) + if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, &pair)) { switch(pair->state) { @@ -1389,7 +1389,7 @@ METHOD(connect_manager_t, process_check, void, this->mutex->lock(this->mutex); check_list_t *checklist; - if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS) + if (!get_checklist_by_id(this, check->connect_id, &checklist)) { DBG1(DBG_IKE, "checklist with id '%#B' not found", &check->connect_id); @@ -1423,6 +1423,15 @@ METHOD(connect_manager_t, process_check, void, check_destroy(check); } +CALLBACK(id_matches, bool, + ike_sa_id_t *a, va_list args) +{ + ike_sa_id_t *b; + + VA_ARGS_VGET(args, b); + return a->equals(a, b); +} + METHOD(connect_manager_t, check_and_register, bool, private_connect_manager_t *this, identification_t *id, identification_t *peer_id, ike_sa_id_t *mediated_sa) @@ -1432,7 +1441,7 @@ METHOD(connect_manager_t, check_and_register, bool, this->mutex->lock(this->mutex); - if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) + if (!get_initiated_by_ids(this, id, peer_id, &initiated)) { DBG2(DBG_IKE, "registered waiting mediated connection with '%Y'", peer_id); @@ -1441,9 +1450,8 @@ METHOD(connect_manager_t, check_and_register, bool, already_there = FALSE; } - if (initiated->mediated->find_first(initiated->mediated, - (linked_list_match_t)mediated_sa->equals, - NULL, mediated_sa) != SUCCESS) + if (!initiated->mediated->find_first(initiated->mediated, id_matches, + NULL, mediated_sa)) { initiated->mediated->insert_last(initiated->mediated, mediated_sa->clone(mediated_sa)); @@ -1462,7 +1470,7 @@ METHOD(connect_manager_t, check_and_initiate, void, this->mutex->lock(this->mutex); - if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) + if (!get_initiated_by_ids(this, id, peer_id, &initiated)) { DBG2(DBG_IKE, "no waiting mediated connections with '%Y'", peer_id); this->mutex->unlock(this->mutex); @@ -1492,7 +1500,7 @@ METHOD(connect_manager_t, set_initiator_data, status_t, this->mutex->lock(this->mutex); - if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS) + if (get_checklist_by_id(this, connect_id, NULL)) { DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting", &connect_id); @@ -1517,7 +1525,7 @@ METHOD(connect_manager_t, set_responder_data, status_t, this->mutex->lock(this->mutex); - if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) + if (!get_checklist_by_id(this, connect_id, &checklist)) { DBG1(DBG_IKE, "checklist with id '%#B' not found", &connect_id); @@ -1547,7 +1555,7 @@ METHOD(connect_manager_t, stop_checks, status_t, this->mutex->lock(this->mutex); - if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) + if (!get_checklist_by_id(this, connect_id, &checklist)) { DBG1(DBG_IKE, "checklist with id '%#B' not found", &connect_id); diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index e4a16faf0..c2ddbc588 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -161,6 +161,16 @@ struct private_task_manager_t { double retransmit_base; /** + * Jitter to apply to calculated retransmit timeout (in percent) + */ + u_int retransmit_jitter; + + /** + * Limit retransmit timeout to this value + */ + uint32_t retransmit_limit; + + /** * Use make-before-break instead of break-before-make reauth? */ bool make_before_break; @@ -321,7 +331,7 @@ METHOD(task_manager_t, retransmit, status_t, if (message_id == this->initiating.mid && array_count(this->initiating.packets)) { - uint32_t timeout; + uint32_t timeout, max_jitter; job_t *job; enumerator_t *enumerator; packet_t *packet; @@ -351,6 +361,16 @@ METHOD(task_manager_t, retransmit, status_t, { timeout = (uint32_t)(this->retransmit_timeout * 1000.0 * pow(this->retransmit_base, this->initiating.retransmitted)); + + if (this->retransmit_limit) + { + timeout = min(timeout, this->retransmit_limit); + } + if (this->retransmit_jitter) + { + max_jitter = (timeout / 100.0) * this->retransmit_jitter; + timeout -= max_jitter * (random() / (RAND_MAX + 1.0)); + } } else { @@ -2059,13 +2079,20 @@ METHOD(task_manager_t, reset, void, this->reset = TRUE; } -/** - * Filter queued tasks - */ -static bool filter_queued(void *unused, queued_task_t **queued, task_t **task) +CALLBACK(filter_queued, bool, + void *unused, enumerator_t *orig, va_list args) { - *task = (*queued)->task; - return TRUE; + queued_task_t *queued; + task_t **task; + + VA_ARGS_VGET(args, task); + + if (orig->enumerate(orig, &queued)) + { + *task = queued->task; + return TRUE; + } + return FALSE; } METHOD(task_manager_t, create_task_enumerator, enumerator_t*, @@ -2080,7 +2107,7 @@ METHOD(task_manager_t, create_task_enumerator, enumerator_t*, case TASK_QUEUE_QUEUED: return enumerator_create_filter( array_create_enumerator(this->queued_tasks), - (void*)filter_queued, NULL, NULL); + filter_queued, NULL, NULL); default: return enumerator_create_empty(); } @@ -2151,6 +2178,10 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns), .retransmit_base = lib->settings->get_double(lib->settings, "%s.retransmit_base", RETRANSMIT_BASE, lib->ns), + .retransmit_jitter = min(lib->settings->get_int(lib->settings, + "%s.retransmit_jitter", 0, lib->ns), RETRANSMIT_JITTER_MAX), + .retransmit_limit = lib->settings->get_int(lib->settings, + "%s.retransmit_limit", 0, lib->ns) * 1000, .make_before_break = lib->settings->get_bool(lib->settings, "%s.make_before_break", FALSE, lib->ns), ); diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index 71cb6b8ea..896cabb2b 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2016 Tobias Brunner + * Copyright (C) 2008-2017 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * HSR Hochschule fuer Technik Rapperswil @@ -602,7 +602,7 @@ static status_t select_and_install(private_child_create_t *this, switch (this->mode) { case MODE_TRANSPORT: - if (!this->config->use_proxy_mode(this->config) && + if (!this->config->has_option(this->config, OPT_PROXY_MODE) && (!ts_list_is_host(this->tsi, other) || !ts_list_is_host(this->tsr, me)) ) @@ -630,6 +630,32 @@ static status_t select_and_install(private_child_create_t *this, default: break; } + /* use a copy of the traffic selectors, as the POST hook should not + * change payloads */ + my_ts = this->tsr->clone_offset(this->tsr, + offsetof(traffic_selector_t, clone)); + other_ts = this->tsi->clone_offset(this->tsi, + offsetof(traffic_selector_t, clone)); + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_RESPONDER_POST, my_ts, other_ts); + + if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0) + { + my_ts->destroy_offset(my_ts, + offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, + offsetof(traffic_selector_t, destroy)); + return NOT_FOUND; + } + } + + this->child_sa->set_policies(this->child_sa, my_ts, other_ts); + if (!this->initiator) + { + my_ts->destroy_offset(my_ts, + offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, + offsetof(traffic_selector_t, destroy)); } this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); @@ -651,19 +677,30 @@ static status_t select_and_install(private_child_create_t *this, { status_i = this->child_sa->install(this->child_sa, encr_r, integ_r, this->my_spi, this->my_cpi, this->initiator, - TRUE, this->tfcv3, my_ts, other_ts); + TRUE, this->tfcv3); status_o = this->child_sa->install(this->child_sa, encr_i, integ_i, this->other_spi, this->other_cpi, this->initiator, - FALSE, this->tfcv3, my_ts, other_ts); + FALSE, this->tfcv3); } - else + else if (!this->rekey) { status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, this->my_spi, this->my_cpi, this->initiator, - TRUE, this->tfcv3, my_ts, other_ts); + TRUE, this->tfcv3); status_o = this->child_sa->install(this->child_sa, encr_r, integ_r, this->other_spi, this->other_cpi, this->initiator, - FALSE, this->tfcv3, my_ts, other_ts); + FALSE, this->tfcv3); + } + else + { /* as responder during a rekeying we only install the inbound + * SA now, the outbound SA and policies are installed when we + * receive the delete for the old SA */ + status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, + this->my_spi, this->my_cpi, this->initiator, + TRUE, this->tfcv3); + this->child_sa->register_outbound(this->child_sa, encr_r, integ_r, + this->other_spi, this->other_cpi, this->tfcv3); + status_o = SUCCESS; } } @@ -679,36 +716,8 @@ static status_t select_and_install(private_child_create_t *this, } else { - if (this->initiator) - { - status = this->child_sa->add_policies(this->child_sa, - my_ts, other_ts); - } - else - { - /* use a copy of the traffic selectors, as the POST hook should not - * change payloads */ - my_ts = this->tsr->clone_offset(this->tsr, - offsetof(traffic_selector_t, clone)); - other_ts = this->tsi->clone_offset(this->tsi, - offsetof(traffic_selector_t, clone)); - charon->bus->narrow(charon->bus, this->child_sa, - NARROW_RESPONDER_POST, my_ts, other_ts); - if (my_ts->get_count(my_ts) == 0 || - other_ts->get_count(other_ts) == 0) - { - status = FAILED; - } - else - { - status = this->child_sa->add_policies(this->child_sa, - my_ts, other_ts); - } - my_ts->destroy_offset(my_ts, - offsetof(traffic_selector_t, destroy)); - other_ts->destroy_offset(other_ts, - offsetof(traffic_selector_t, destroy)); - } + status = this->child_sa->install_policies(this->child_sa); + if (status != SUCCESS) { DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); @@ -736,7 +745,6 @@ static status_t select_and_install(private_child_create_t *this, charon->bus->child_keys(charon->bus, this->child_sa, this->initiator, this->dh, nonce_i, nonce_r); - /* add to IKE_SA, and remove from task */ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); this->established = TRUE; @@ -748,16 +756,17 @@ static status_t select_and_install(private_child_create_t *this, other_ts = linked_list_create_from_enumerator( this->child_sa->create_ts_enumerator(this->child_sa, FALSE)); - DBG0(DBG_IKE, "CHILD_SA %s{%d} established " + DBG0(DBG_IKE, "%sCHILD_SA %s{%d} established " "with SPIs %.8x_i %.8x_o and TS %#R === %#R", + this->rekey && !this->initiator ? "inbound " : "", this->child_sa->get_name(this->child_sa), this->child_sa->get_unique_id(this->child_sa), ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), - ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts); + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + my_ts, other_ts); my_ts->destroy(my_ts); other_ts->destroy(other_ts); - return SUCCESS; } @@ -1073,7 +1082,7 @@ METHOD(task_t, build_i, status_t, this->dh_group); } - if (this->config->use_ipcomp(this->config)) + if (this->config->has_option(this->config, OPT_IPCOMP)) { /* IPCOMP_DEFLATE is the only transform we support at the moment */ add_ipcomp_notify(this, message, IPCOMP_DEFLATE); @@ -1327,7 +1336,7 @@ METHOD(task_t, build_r, status_t, if (this->ipcomp_received != IPCOMP_NONE) { - if (this->config->use_ipcomp(this->config)) + if (this->config->has_option(this->config, OPT_IPCOMP)) { add_ipcomp_notify(this, message, this->ipcomp_received); } @@ -1690,7 +1699,6 @@ METHOD(task_t, destroy, void, { this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); } - DESTROY_IF(this->config); DESTROY_IF(this->nonceg); free(this); diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c index 6fa8836ac..626796383 100644 --- a/src/libcharon/sa/ikev2/tasks/child_delete.c +++ b/src/libcharon/sa/ikev2/tasks/child_delete.c @@ -18,9 +18,14 @@ #include <daemon.h> #include <encoding/payloads/delete_payload.h> +#include <processing/jobs/delete_child_sa_job.h> #include <sa/ikev2/tasks/child_create.h> #include <sa/ikev2/tasks/child_rekey.h> +#ifndef DELETE_REKEYED_DELAY +#define DELETE_REKEYED_DELAY 5 +#endif + typedef struct private_child_delete_t private_child_delete_t; /** @@ -39,67 +44,80 @@ struct private_child_delete_t { ike_sa_t *ike_sa; /** - * Are we the initiator? + * Whether we are the initiator of the exchange */ bool initiator; /** - * Protocol of CHILD_SA to delete + * Protocol of CHILD_SA to delete (as initiator) */ protocol_id_t protocol; /** - * Inbound SPI of CHILD_SA to delete + * Inbound SPI of CHILD_SA to delete (as initiator) */ uint32_t spi; /** - * whether to enforce delete action policy - */ - bool check_delete_action; - - /** - * is this delete exchange following a rekey? - */ - bool rekeyed; - - /** - * CHILD_SA already expired? + * CHILD_SA already expired (as initiator) */ bool expired; /** - * CHILD_SAs which get deleted + * CHILD_SAs which get deleted, entry_t* */ linked_list_t *child_sas; }; /** + * Information about a deleted CHILD_SA + */ +typedef struct { + /** Deleted CHILD_SA */ + child_sa_t *child_sa; + /** Whether the CHILD_SA was rekeyed */ + bool rekeyed; + /** Whether to enforce any delete action policy */ + bool check_delete_action; +} entry_t; + +CALLBACK(match_child, bool, + entry_t *entry, va_list args) +{ + child_sa_t *child_sa; + + VA_ARGS_VGET(args, child_sa); + return entry->child_sa == child_sa; +} + +/** * build the delete payloads from the listed child_sas */ static void build_payloads(private_child_delete_t *this, message_t *message) { delete_payload_t *ah = NULL, *esp = NULL; enumerator_t *enumerator; - child_sa_t *child_sa; + entry_t *entry; + protocol_id_t protocol; + uint32_t spi; enumerator = this->child_sas->create_enumerator(this->child_sas); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) + while (enumerator->enumerate(enumerator, (void**)&entry)) { - protocol_id_t protocol = child_sa->get_protocol(child_sa); - uint32_t spi = child_sa->get_spi(child_sa, TRUE); + protocol = entry->child_sa->get_protocol(entry->child_sa); + spi = entry->child_sa->get_spi(entry->child_sa, TRUE); switch (protocol) { case PROTO_ESP: - if (esp == NULL) + if (!esp) { esp = delete_payload_create(PLV2_DELETE, PROTO_ESP); message->add_payload(message, (payload_t*)esp); } esp->add_spi(esp, spi); DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", - protocol_id_names, protocol, ntohl(spi)); + protocol_id_names, protocol, ntohl(spi)); break; case PROTO_AH: if (ah == NULL) @@ -109,12 +127,12 @@ static void build_payloads(private_child_delete_t *this, message_t *message) } ah->add_spi(ah, spi); DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", - protocol_id_names, protocol, ntohl(spi)); + protocol_id_names, protocol, ntohl(spi)); break; default: break; } - child_sa->set_state(child_sa, CHILD_DELETING); + entry->child_sa->set_state(entry->child_sa, CHILD_DELETING); } enumerator->destroy(enumerator); } @@ -147,6 +165,57 @@ static bool is_redundant(private_child_delete_t *this, child_sa_t *child) } /** + * Install the outbound CHILD_SA with the given SPI + */ +static void install_outbound(private_child_delete_t *this, + protocol_id_t protocol, uint32_t spi) +{ + child_sa_t *child_sa; + linked_list_t *my_ts, *other_ts; + status_t status; + + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, + spi, FALSE); + if (!child_sa) + { + DBG1(DBG_IKE, "CHILD_SA not found after rekeying"); + return; + } + if (this->initiator && is_redundant(this, child_sa)) + { /* if we won the rekey collision we don't want to install the + * redundant SA created by the peer */ + return; + } + + status = child_sa->install_outbound(child_sa); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel"); + charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED, + child_sa); + /* FIXME: delete the new child_sa? */ + return; + } + child_sa->set_state(child_sa, CHILD_INSTALLED); + + my_ts = linked_list_create_from_enumerator( + child_sa->create_ts_enumerator(child_sa, TRUE)); + other_ts = linked_list_create_from_enumerator( + child_sa->create_ts_enumerator(child_sa, FALSE)); + + DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R === %#R", + child_sa->get_name(child_sa), + child_sa->get_unique_id(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), + ntohl(child_sa->get_spi(child_sa, FALSE)), + my_ts, other_ts); + + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); +} + +/** * read in payloads and find the children to delete */ static void process_payloads(private_child_delete_t *this, message_t *message) @@ -157,6 +226,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message) uint32_t spi; protocol_id_t protocol; child_sa_t *child_sa; + entry_t *entry; payloads = message->create_payload_enumerator(message); while (payloads->enumerate(payloads, &payload)) @@ -174,27 +244,37 @@ static void process_payloads(private_child_delete_t *this, message_t *message) { child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE); - if (child_sa == NULL) + if (!child_sa) { - DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, " - "but no such SA", protocol_id_names, protocol, ntohl(spi)); + DBG1(DBG_IKE, "received DELETE for unknown %N CHILD_SA with" + " SPI %.8x", protocol_id_names, protocol, ntohl(spi)); continue; } DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x", protocol_id_names, protocol, ntohl(spi)); + if (this->child_sas->find_first(this->child_sas, match_child, + NULL, child_sa)) + { + continue; + } + INIT(entry, + .child_sa = child_sa + ); switch (child_sa->get_state(child_sa)) { case CHILD_REKEYED: - this->rekeyed = TRUE; + entry->rekeyed = TRUE; break; case CHILD_DELETING: - /* we don't send back a delete if we initiated ourself */ + /* we don't send back a delete if we already initiated + * a delete ourself */ if (!this->initiator) { + free(entry); continue; } - /* fall through */ + break; case CHILD_REKEYING: /* we reply as usual, rekeying will fail */ case CHILD_INSTALLED: @@ -202,22 +282,18 @@ static void process_payloads(private_child_delete_t *this, message_t *message) { if (is_redundant(this, child_sa)) { - this->rekeyed = TRUE; + entry->rekeyed = TRUE; } else { - this->check_delete_action = TRUE; + entry->check_delete_action = TRUE; } } break; default: break; } - if (this->child_sas->find_first(this->child_sas, NULL, - (void**)&child_sa) != SUCCESS) - { - this->child_sas->insert_last(this->child_sas, child_sa); - } + this->child_sas->insert_last(this->child_sas, entry); } spis->destroy(spis); } @@ -231,29 +307,64 @@ static void process_payloads(private_child_delete_t *this, message_t *message) static status_t destroy_and_reestablish(private_child_delete_t *this) { enumerator_t *enumerator; + entry_t *entry; child_sa_t *child_sa; child_cfg_t *child_cfg; protocol_id_t protocol; - uint32_t spi, reqid; + uint32_t spi, reqid, rekey_spi; action_t action; status_t status = SUCCESS; + time_t now, expire; + u_int delay; + + now = time_monotonic(NULL); + delay = lib->settings->get_int(lib->settings, "%s.delete_rekeyed_delay", + DELETE_REKEYED_DELAY, lib->ns); enumerator = this->child_sas->create_enumerator(this->child_sas); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) + while (enumerator->enumerate(enumerator, (void**)&entry)) { + child_sa = entry->child_sa; /* signal child down event if we weren't rekeying */ - if (!this->rekeyed) + protocol = child_sa->get_protocol(child_sa); + if (!entry->rekeyed) { charon->bus->child_updown(charon->bus, child_sa, FALSE); } + else + { + rekey_spi = child_sa->get_rekey_spi(child_sa); + if (rekey_spi) + { + install_outbound(this, protocol, rekey_spi); + } + /* for rekeyed CHILD_SAs we uninstall the outbound SA but don't + * immediately destroy it, by default, so we can process delayed + * packets */ + child_sa->remove_outbound(child_sa); + expire = child_sa->get_lifetime(child_sa, TRUE); + if (delay && (!expire || ((now + delay) < expire))) + { + lib->scheduler->schedule_job(lib->scheduler, + (job_t*)delete_child_sa_job_create_id( + child_sa->get_unique_id(child_sa)), delay); + continue; + } + else if (expire) + { /* let it expire naturally */ + continue; + } + /* no delay and no lifetime, destroy it immediately */ + } spi = child_sa->get_spi(child_sa, TRUE); reqid = child_sa->get_reqid(child_sa); - protocol = child_sa->get_protocol(child_sa); child_cfg = child_sa->get_config(child_sa); child_cfg->get_ref(child_cfg); action = child_sa->get_close_action(child_sa); + this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi); - if (this->check_delete_action) + + if (entry->check_delete_action) { /* enforce child_cfg policy if deleted passively */ switch (action) { @@ -288,12 +399,14 @@ static void log_children(private_child_delete_t *this) { linked_list_t *my_ts, *other_ts; enumerator_t *enumerator; + entry_t *entry; child_sa_t *child_sa; uint64_t bytes_in, bytes_out; enumerator = this->child_sas->create_enumerator(this->child_sas); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) + while (enumerator->enumerate(enumerator, (void**)&entry)) { + child_sa = entry->child_sa; my_ts = linked_list_create_from_enumerator( child_sa->create_ts_enumerator(child_sa, TRUE)); other_ts = linked_list_create_from_enumerator( @@ -328,6 +441,7 @@ METHOD(task_t, build_i, status_t, private_child_delete_t *this, message_t *message) { child_sa_t *child_sa; + entry_t *entry; child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, this->spi, TRUE); @@ -342,15 +456,24 @@ METHOD(task_t, build_i, status_t, /* we work only with the inbound SPI */ this->spi = child_sa->get_spi(child_sa, TRUE); } - this->child_sas->insert_last(this->child_sas, child_sa); - if (child_sa->get_state(child_sa) == CHILD_REKEYED) - { - this->rekeyed = TRUE; + + if (child_sa->get_state(child_sa) == CHILD_DELETING) + { /* DELETEs for this CHILD_SA were already exchanged, but it was not yet + * destroyed to allow delayed packets to get processed */ + this->ike_sa->destroy_child_sa(this->ike_sa, this->protocol, this->spi); + message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED); + return SUCCESS; } + + INIT(entry, + .child_sa = child_sa, + .rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYED, + ); + this->child_sas->insert_last(this->child_sas, entry); log_children(this); build_payloads(this, message); - if (!this->rekeyed && this->expired) + if (!entry->rekeyed && this->expired) { child_cfg_t *child_cfg; @@ -397,24 +520,28 @@ METHOD(child_delete_t , get_child, child_sa_t*, private_child_delete_t *this) { child_sa_t *child_sa = NULL; - this->child_sas->get_first(this->child_sas, (void**)&child_sa); + entry_t *entry; + + if (this->child_sas->get_first(this->child_sas, (void**)&entry) == SUCCESS) + { + child_sa = entry->child_sa; + } return child_sa; } METHOD(task_t, migrate, void, private_child_delete_t *this, ike_sa_t *ike_sa) { - this->check_delete_action = FALSE; this->ike_sa = ike_sa; - this->child_sas->destroy(this->child_sas); + this->child_sas->destroy_function(this->child_sas, free); this->child_sas = linked_list_create(); } METHOD(task_t, destroy, void, private_child_delete_t *this) { - this->child_sas->destroy(this->child_sas); + this->child_sas->destroy_function(this->child_sas, free); free(this); } diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c index c04ec141f..761c860e7 100644 --- a/src/libcharon/sa/ikev2/tasks/child_rekey.c +++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c @@ -132,6 +132,7 @@ static void find_child(private_child_rekey_t *this, message_t *message) notify_payload_t *notify; protocol_id_t protocol; uint32_t spi; + child_sa_t *child_sa; notify = message->get_notify(message, REKEY_SA); if (notify) @@ -141,8 +142,15 @@ static void find_child(private_child_rekey_t *this, message_t *message) if (protocol == PROTO_ESP || protocol == PROTO_AH) { - this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, - spi, FALSE); + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, + spi, FALSE); + if (child_sa && + child_sa->get_state(child_sa) == CHILD_DELETING && + child_sa->get_outbound_state(child_sa) == CHILD_OUTBOUND_NONE) + { /* ignore rekeyed CHILD_SAs we keep around */ + return; + } + this->child_sa = child_sa; } } } @@ -227,6 +235,7 @@ METHOD(task_t, build_r, status_t, child_cfg_t *config; uint32_t reqid; child_sa_state_t state; + child_sa_t *child_sa; if (!this->child_sa) { @@ -260,7 +269,10 @@ METHOD(task_t, build_r, status_t, return SUCCESS; } + child_sa = this->child_create->get_child(this->child_create); this->child_sa->set_state(this->child_sa, CHILD_REKEYED); + this->child_sa->set_rekey_spi(this->child_sa, + child_sa->get_spi(child_sa, FALSE)); /* invoke rekey hook */ charon->bus->child_rekey(charon->bus, this->child_sa, diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index b0162751d..ad12f0579 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -381,14 +381,24 @@ METHOD(shunt_manager_t, uninstall, bool, } CALLBACK(filter_entries, bool, - void *unused, entry_t **entry, char **ns, void **in, child_cfg_t **cfg) + void *unused, enumerator_t *orig, va_list args) { - if (ns) + entry_t *entry; + child_cfg_t **cfg; + char **ns; + + VA_ARGS_VGET(args, ns, cfg); + + if (orig->enumerate(orig, &entry)) { - *ns = (*entry)->ns; + if (ns) + { + *ns = entry->ns; + } + *cfg = entry->cfg; + return TRUE; } - *cfg = (*entry)->cfg; - return TRUE; + return FALSE; } METHOD(shunt_manager_t, create_enumerator, enumerator_t*, @@ -397,7 +407,7 @@ METHOD(shunt_manager_t, create_enumerator, enumerator_t*, this->lock->read_lock(this->lock); return enumerator_create_filter( this->shunts->create_enumerator(this->shunts), - (void*)filter_entries, this->lock, + filter_entries, this->lock, (void*)this->lock->unlock); } diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index c42008ba9..bd1191406 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -15,10 +15,40 @@ #include "task_manager.h" +#include <math.h> #include <sa/ikev1/task_manager_v1.h> #include <sa/ikev2/task_manager_v2.h> -/** +/* + * See header + */ +u_int task_manager_total_retransmit_timeout() +{ + double timeout, base, limit = 0, total = 0; + int tries, i; + + tries = lib->settings->get_int(lib->settings, "%s.retransmit_tries", + RETRANSMIT_TRIES, lib->ns); + base = lib->settings->get_double(lib->settings, "%s.retransmit_base", + RETRANSMIT_BASE, lib->ns); + timeout = lib->settings->get_double(lib->settings, "%s.retransmit_timeout", + RETRANSMIT_TIMEOUT, lib->ns); + limit = lib->settings->get_double(lib->settings, "%s.retransmit_limit", + 0, lib->ns); + + for (i = 0; i <= tries; i++) + { + double interval = timeout * pow(base, i); + if (limit) + { + interval = min(interval, limit); + } + total += interval; + } + return (u_int)total; +} + +/* * See header */ task_manager_t *task_manager_create(ike_sa_t *ike_sa) diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 7e9262291..e3fddf39b 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -48,6 +48,11 @@ typedef enum task_queue_t task_queue_t; #define RETRANSMIT_TRIES 5 /** + * Maximum jitter in percent. + */ +#define RETRANSMIT_JITTER_MAX 20 + +/** * Interval for mobike routability checks in ms. */ #define ROUTEABILITY_CHECK_INTERVAL 2500 @@ -298,6 +303,17 @@ struct task_manager_t { }; /** + * Calculate total timeout of the retransmission mechanism. + * + * This is affected by modifications of retransmit_base, retransmit_timeout, + * retransmit_limit or retransmit_tries. The resulting value can then be used + * e.g. in kernel plugins to set the system's acquire timeout properly. + * + * @return calculated total retransmission timeout in seconds + */ +u_int task_manager_total_retransmit_timeout(); + +/** * Create a task manager instance for the correct IKE version. * * @param ike_sa IKE_SA to create a task manager for diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index 40a0682f2..f9fee5e7e 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -140,19 +140,21 @@ static void destroy_acquire(acquire_t *this) free(this); } -/** - * match an acquire entry by reqid - */ -static bool acquire_by_reqid(acquire_t *this, uint32_t *reqid) +CALLBACK(acquire_by_reqid, bool, + acquire_t *this, va_list args) { - return this->reqid == *reqid; + uint32_t reqid; + + VA_ARGS_VGET(args, reqid); + return this->reqid == reqid; } -/** - * match an acquire entry by destination address - */ -static bool acquire_by_dst(acquire_t *this, host_t *dst) +CALLBACK(acquire_by_dst, bool, + acquire_t *this, va_list args) { + host_t *dst; + + VA_ARGS_VGET(args, dst); return this->dst && this->dst->ip_equals(this->dst, dst); } @@ -272,7 +274,8 @@ METHOD(trap_manager_t, install, uint32_t, proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); child_sa->set_protocol(child_sa, proto); child_sa->set_mode(child_sa, child->get_mode(child)); - status = child_sa->add_policies(child_sa, my_ts, other_ts); + child_sa->set_policies(child_sa, my_ts, other_ts); + status = child_sa->install_policies(child_sa); my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); if (status != SUCCESS) @@ -334,25 +337,32 @@ METHOD(trap_manager_t, uninstall, bool, return TRUE; } -/** - * convert enumerated entries to peer_cfg, child_sa - */ -static bool trap_filter(rwlock_t *lock, entry_t **entry, peer_cfg_t **peer_cfg, - void *none, child_sa_t **child_sa) +CALLBACK(trap_filter, bool, + rwlock_t *lock, enumerator_t *orig, va_list args) { - if (!(*entry)->child_sa) - { /* skip entries that are currently being installed */ - return FALSE; - } - if (peer_cfg) - { - *peer_cfg = (*entry)->peer_cfg; - } - if (child_sa) + entry_t *entry; + peer_cfg_t **peer_cfg; + child_sa_t **child_sa; + + VA_ARGS_VGET(args, peer_cfg, child_sa); + + while (orig->enumerate(orig, &entry)) { - *child_sa = (*entry)->child_sa; + if (!entry->child_sa) + { /* skip entries that are currently being installed */ + continue; + } + if (peer_cfg) + { + *peer_cfg = entry->peer_cfg; + } + if (child_sa) + { + *child_sa = entry->child_sa; + } + return TRUE; } - return TRUE; + return FALSE; } METHOD(trap_manager_t, create_enumerator, enumerator_t*, @@ -360,7 +370,7 @@ METHOD(trap_manager_t, create_enumerator, enumerator_t*, { this->lock->read_lock(this->lock); return enumerator_create_filter(this->traps->create_enumerator(this->traps), - (void*)trap_filter, this->lock, + trap_filter, this->lock, (void*)this->lock->unlock); } @@ -431,8 +441,8 @@ METHOD(trap_manager_t, acquire, void, uint8_t mask; dst->to_subnet(dst, &host, &mask); - if (this->acquires->find_first(this->acquires, (void*)acquire_by_dst, - (void**)&acquire, host) == SUCCESS) + if (this->acquires->find_first(this->acquires, acquire_by_dst, + (void**)&acquire, host)) { host->destroy(host); ignore = TRUE; @@ -448,8 +458,8 @@ METHOD(trap_manager_t, acquire, void, } else { - if (this->acquires->find_first(this->acquires, (void*)acquire_by_reqid, - (void**)&acquire, &reqid) == SUCCESS) + if (this->acquires->find_first(this->acquires, acquire_by_reqid, + (void**)&acquire, reqid)) { ignore = TRUE; } diff --git a/src/libcharon/tests/Makefile.in b/src/libcharon/tests/Makefile.in index e922a7171..3070f429b 100644 --- a/src/libcharon/tests/Makefile.in +++ b/src/libcharon/tests/Makefile.in @@ -380,6 +380,7 @@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ +fuzz_plugins = @fuzz_plugins@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ host = @host@ @@ -402,6 +403,7 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libfuzzer = @libfuzzer@ libiptc_CFLAGS = @libiptc_CFLAGS@ libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ diff --git a/src/libcharon/tests/suites/test_child_rekey.c b/src/libcharon/tests/suites/test_child_rekey.c index fcac49388..76b23f589 100644 --- a/src/libcharon/tests/suites/test_child_rekey.c +++ b/src/libcharon/tests/suites/test_child_rekey.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Tobias Brunner + * Copyright (C) 2016-2017 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -28,7 +28,23 @@ assert_hook_not_called(child_updown); \ assert_hook_not_called(child_rekey); \ call_ikesa(sa, rekey_child_sa, PROTO_ESP, spi); \ - assert_child_sa_state(sa, spi, CHILD_REKEYING); \ + assert_child_sa_state(sa, spi, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); \ + assert_hook(); \ + assert_hook(); \ +}) + +/** + * Destroy a rekeyed CHILD_SA that was kept around to accept inbound traffic. + * Simulates the job that's scheduled to do this. + */ +#define destroy_rekeyed(sa, spi) ({ \ + assert_hook_not_called(child_updown); \ + assert_hook_not_called(child_rekey); \ + assert_no_jobs_scheduled(); \ + assert_child_sa_state(sa, spi, CHILD_DELETING, CHILD_OUTBOUND_NONE); \ + call_ikesa(sa, delete_child_sa, PROTO_ESP, spi, FALSE); \ + assert_child_sa_not_exists(sa, spi); \ + assert_scheduler(); \ assert_hook(); \ assert_hook(); \ }) @@ -53,6 +69,7 @@ START_TEST(test_regular) &a, &b, NULL); } initiate_rekey(a, spi_a); + assert_ipsec_sas_installed(a, spi_a, spi_b); /* this should never get called as this results in a successful rekeying */ assert_hook_not_called(child_updown); @@ -61,33 +78,51 @@ START_TEST(test_regular) assert_hook_called(child_rekey); assert_notify(IN, REKEY_SA); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, spi_b, CHILD_REKEYED); - assert_child_sa_state(b, 4, CHILD_INSTALLED); + assert_child_sa_state(b, spi_b, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, spi_a, spi_b, 4); assert_hook(); /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */ assert_hook_called(child_rekey); assert_no_notify(IN, REKEY_SA); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, spi_a, CHILD_DELETING); - assert_child_sa_state(a, 3, CHILD_INSTALLED); + assert_child_sa_state(a, spi_a, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, spi_a, spi_b, 3, 4); assert_hook(); /* INFORMATIONAL { D } --> */ assert_hook_not_called(child_rekey); + assert_jobs_scheduled(1); assert_single_payload(IN, PLV2_DELETE); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 4, CHILD_INSTALLED); - assert_child_sa_count(b, 1); + assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 2); + assert_ipsec_sas_installed(b, spi_b, 3, 4); + assert_scheduler(); assert_hook(); /* <-- INFORMATIONAL { D } */ assert_hook_not_called(child_rekey); + assert_jobs_scheduled(1); assert_single_payload(IN, PLV2_DELETE); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 3, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, spi_a, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 2); + assert_ipsec_sas_installed(a, spi_a, 3, 4); + assert_scheduler(); assert_hook(); + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, spi_a); + assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, 3, 4); + destroy_rekeyed(b, spi_b); + assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(a, 3, 4); + /* child_updown */ assert_hook(); @@ -125,6 +160,7 @@ START_TEST(test_regular_ke_invalid) &a, &b, &conf); } initiate_rekey(a, spi_a); + assert_ipsec_sas_installed(a, spi_a, spi_b); /* this should never get called as this results in a successful rekeying */ assert_hook_not_called(child_updown); @@ -135,6 +171,7 @@ START_TEST(test_regular_ke_invalid) exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_child_sa_state(b, spi_b, CHILD_INSTALLED); assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, spi_a, spi_b); assert_hook(); /* <-- CREATE_CHILD_SA { N(INVAL_KE) } */ @@ -143,6 +180,7 @@ START_TEST(test_regular_ke_invalid) exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_child_sa_state(a, spi_a, CHILD_REKEYING); assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, spi_a, spi_b); assert_hook(); /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */ @@ -150,7 +188,8 @@ START_TEST(test_regular_ke_invalid) assert_notify(IN, REKEY_SA); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_child_sa_state(b, spi_b, CHILD_REKEYED); - assert_child_sa_state(b, 6, CHILD_INSTALLED); + assert_child_sa_state(b, 6, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, spi_a, spi_b, 6); assert_hook(); /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */ @@ -158,24 +197,37 @@ START_TEST(test_regular_ke_invalid) assert_no_notify(IN, REKEY_SA); exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_child_sa_state(a, spi_a, CHILD_DELETING); - assert_child_sa_state(a, 5, CHILD_INSTALLED); + assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, spi_a, spi_b, 5, 6); assert_hook(); /* INFORMATIONAL { D } --> */ assert_hook_not_called(child_rekey); assert_single_payload(IN, PLV2_DELETE); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 6, CHILD_INSTALLED); - assert_child_sa_count(b, 1); + assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, 6, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 2); + assert_ipsec_sas_installed(b, spi_b, 5, 6); assert_hook(); /* <-- INFORMATIONAL { D } */ assert_hook_not_called(child_rekey); assert_single_payload(IN, PLV2_DELETE); exchange_test_helper->process_message(exchange_test_helper, a, NULL); + assert_child_sa_state(a, spi_a, CHILD_DELETING, CHILD_OUTBOUND_NONE); assert_child_sa_state(a, 5, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_count(a, 2); + assert_ipsec_sas_installed(a, spi_a, 5, 6); assert_hook(); + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, spi_a); + assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, 5, 6); + destroy_rekeyed(b, spi_b); + assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, 5, 6); + /* child_updown */ assert_hook(); @@ -195,6 +247,7 @@ START_TEST(test_regular_responder_ignore_soft_expire) exchange_test_helper->establish_sa(exchange_test_helper, &a, &b, NULL); initiate_rekey(a, 1); + assert_ipsec_sas_installed(a, 1, 2); /* this should never get called as this results in a successful rekeying */ assert_hook_not_called(child_updown); @@ -204,7 +257,8 @@ START_TEST(test_regular_responder_ignore_soft_expire) assert_notify(IN, REKEY_SA); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_child_sa_state(b, 2, CHILD_REKEYED); - assert_child_sa_state(b, 4, CHILD_INSTALLED); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, 1, 2, 4); assert_hook(); /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */ @@ -212,7 +266,8 @@ START_TEST(test_regular_responder_ignore_soft_expire) assert_no_notify(IN, REKEY_SA); exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_child_sa_state(a, 1, CHILD_DELETING); - assert_child_sa_state(a, 3, CHILD_INSTALLED); + assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, 1, 2, 3, 4); assert_hook(); /* we don't expect this to get called anymore */ @@ -223,15 +278,31 @@ START_TEST(test_regular_responder_ignore_soft_expire) assert_child_sa_state(b, 2, CHILD_REKEYED); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); assert_single_payload(IN, PLV2_DELETE); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 4, CHILD_INSTALLED); - assert_child_sa_count(b, 1); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 2); + assert_ipsec_sas_installed(b, 2, 3, 4); + assert_scheduler(); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); assert_single_payload(IN, PLV2_DELETE); exchange_test_helper->process_message(exchange_test_helper, a, NULL); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); assert_child_sa_state(a, 3, CHILD_INSTALLED); + assert_child_sa_count(a, 2); + assert_ipsec_sas_installed(a, 1, 3, 4); + assert_scheduler(); + + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, 1); assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, 3, 4); + destroy_rekeyed(b, 2); + assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, 3, 4); /* child_rekey/child_updown */ assert_hook(); @@ -254,6 +325,7 @@ START_TEST(test_regular_responder_handle_hard_expire) exchange_test_helper->establish_sa(exchange_test_helper, &a, &b, NULL); initiate_rekey(a, 1); + assert_ipsec_sas_installed(a, 1, 2); /* this should never get called as this results in a successful rekeying */ assert_hook_not_called(child_updown); @@ -263,7 +335,8 @@ START_TEST(test_regular_responder_handle_hard_expire) assert_notify(IN, REKEY_SA); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_child_sa_state(b, 2, CHILD_REKEYED); - assert_child_sa_state(b, 4, CHILD_INSTALLED); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, 1, 2, 4); assert_hook(); /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */ @@ -271,7 +344,8 @@ START_TEST(test_regular_responder_handle_hard_expire) assert_no_notify(IN, REKEY_SA); exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_child_sa_state(a, 1, CHILD_DELETING); - assert_child_sa_state(a, 3, CHILD_INSTALLED); + assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, 1, 2, 3, 4); assert_hook(); /* we don't expect this to get called anymore */ @@ -279,28 +353,51 @@ START_TEST(test_regular_responder_handle_hard_expire) /* this is similar to a regular delete collision */ assert_single_payload(OUT, PLV2_DELETE); call_ikesa(b, delete_child_sa, PROTO_ESP, 2, TRUE); - assert_child_sa_state(b, 2, CHILD_DELETING); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + /* since the SAs expired they would not actually be installed in the kernel + * anymore and since we have not yet installed a new outbound SA this + * will result in dropped packets and possibly acquires */ + assert_ipsec_sas_installed(b, 1, 2, 4); /* INFORMATIONAL { D } --> */ assert_single_payload(IN, PLV2_DELETE); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 4, CHILD_INSTALLED); - assert_child_sa_state(a, 2, CHILD_DELETING); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, 1, 2, 4); /* <-- INFORMATIONAL { D } */ assert_single_payload(IN, PLV2_DELETE); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 3, CHILD_INSTALLED); - assert_child_sa_state(a, 1, CHILD_DELETING); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, 1, 2, 3, 4); /* <-- INFORMATIONAL { } */ + assert_jobs_scheduled(1); assert_message_empty(IN); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 3, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 2); + assert_ipsec_sas_installed(a, 1, 3, 4); + assert_scheduler(); /* INFORMATIONAL { } --> */ + assert_jobs_scheduled(1); assert_message_empty(IN); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 4, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 2); + assert_ipsec_sas_installed(b, 2, 3, 4); + assert_scheduler(); + + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, 1); + assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, 3, 4); + destroy_rekeyed(b, 2); assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, 3, 4); /* child_rekey/child_updown */ assert_hook(); @@ -350,8 +447,10 @@ START_TEST(test_collision) exchange_test_helper->nonce_first_byte = data[_i].nonces[0]; initiate_rekey(a, 1); + assert_ipsec_sas_installed(a, 1, 2); exchange_test_helper->nonce_first_byte = data[_i].nonces[1]; initiate_rekey(b, 2); + assert_ipsec_sas_installed(b, 1, 2); /* this should never get called as this results in a successful rekeying */ assert_hook_not_called(child_updown); @@ -360,15 +459,17 @@ START_TEST(test_collision) exchange_test_helper->nonce_first_byte = data[_i].nonces[2]; assert_hook_rekey(child_rekey, 2, 5); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_REKEYED); - assert_child_sa_state(b, 5, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 5, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, 1, 2, 5); assert_hook(); /* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */ exchange_test_helper->nonce_first_byte = data[_i].nonces[3]; assert_hook_rekey(child_rekey, 1, 6); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYED); - assert_child_sa_state(a, 6, CHILD_INSTALLED); + assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, 6, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(a, 1, 2, 6); assert_hook(); /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */ @@ -378,53 +479,113 @@ START_TEST(test_collision) assert_hook_rekey(child_rekey, 1, data[_i].spi_a); exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_hook(); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED, + CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); } else { assert_hook_not_called(child_rekey); exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_hook(); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_REGISTERED); } - assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING); - assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED); - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, 1, 2, 3, 5, 6); /* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */ if (data[_i].spi_del_b == 2) { assert_hook_rekey(child_rekey, 2, data[_i].spi_b); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_hook(); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED, + CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); } else { assert_hook_not_called(child_rekey); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_hook(); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_REGISTERED); } - assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING); - assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6); /* we don't expect this hook to get called anymore */ assert_hook_not_called(child_rekey); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); - assert_child_sa_count(b, 2); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 3); + assert_ipsec_sas_installed(b, 2, 4, 5, 6, + data[_i].spi_del_b == 2 ? 1 : 3); + assert_scheduler(); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING); - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); - assert_child_sa_count(a, 2); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 3); + assert_ipsec_sas_installed(a, 1, 3, 5, 6, + data[_i].spi_del_a == 1 ? 2 : 4); + assert_scheduler(); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 3); + assert_ipsec_sas_installed(a, 1, 3, 6, + data[_i].spi_del_a == 1 ? 5 : 4); + assert_scheduler(); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 3); + assert_ipsec_sas_installed(b, 2, 4, 5, + data[_i].spi_del_b == 2 ? 6 : 3); + assert_scheduler(); + + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, data[_i].spi_del_a); + destroy_rekeyed(a, data[_i].spi_del_b); + assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, data[_i].spi_a, data[_i].spi_b); + destroy_rekeyed(b, data[_i].spi_del_a); + destroy_rekeyed(b, data[_i].spi_del_b); assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, data[_i].spi_a, data[_i].spi_b); /* child_rekey/child_updown */ assert_hook(); @@ -483,8 +644,10 @@ START_TEST(test_collision_delayed_response) exchange_test_helper->nonce_first_byte = data[_i].nonces[0]; initiate_rekey(a, 1); + assert_ipsec_sas_installed(a, 1, 2); exchange_test_helper->nonce_first_byte = data[_i].nonces[1]; initiate_rekey(b, 2); + assert_ipsec_sas_installed(b, 1, 2); /* this should never get called as this results in a successful rekeying */ assert_hook_not_called(child_updown); @@ -493,15 +656,17 @@ START_TEST(test_collision_delayed_response) exchange_test_helper->nonce_first_byte = data[_i].nonces[2]; assert_hook_rekey(child_rekey, 2, 5); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_REKEYED); - assert_child_sa_state(b, 5, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 5, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, 1, 2, 5); assert_hook(); /* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */ exchange_test_helper->nonce_first_byte = data[_i].nonces[3]; assert_hook_rekey(child_rekey, 1, 6); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYED); - assert_child_sa_state(a, 6, CHILD_INSTALLED); + assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, 6, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(a, 1, 2, 6); assert_hook(); /* delay the CREATE_CHILD_SA response from b to a */ @@ -513,35 +678,68 @@ START_TEST(test_collision_delayed_response) assert_hook_rekey(child_rekey, 2, data[_i].spi_b); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_hook(); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED, + CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); } else { assert_hook_not_called(child_rekey); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_hook(); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_REGISTERED); } - assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING); - assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6); /* <-- INFORMATIONAL { D } */ assert_hook_not_called(child_rekey); + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); if (data[_i].spi_del_b == 2) { - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, 1, 4, 6); } else { - assert_child_sa_state(a, 1, CHILD_REKEYED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_ipsec_sas_installed(a, 1, 2, 6); } + assert_child_sa_count(a, 2); + assert_scheduler(); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); - assert_child_sa_count(b, 2); + if (data[_i].spi_del_b == 2) + { + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED, + CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(b, 2, 4, 5, 6); + } + else + { + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5); + } + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_count(b, 3); + assert_scheduler(); assert_hook(); /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } (delayed) */ @@ -557,20 +755,54 @@ START_TEST(test_collision_delayed_response) exchange_test_helper->process_message(exchange_test_helper, a, msg); assert_hook(); } - assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING); - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); - assert_child_sa_count(a, 2); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, 1, 3, 5, 6, + data[_i].spi_del_a == 1 ? 2 : 4); + assert_child_sa_count(a, 3); /* we don't expect this hook to get called anymore */ assert_hook_not_called(child_rekey); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); - assert_child_sa_count(b, 1); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(b, 2, 4, 5, + data[_i].spi_del_b == 2 ? 6 : 3); + assert_child_sa_count(b, 3); + assert_scheduler(); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 3); + assert_ipsec_sas_installed(a, 1, 3, 6, + data[_i].spi_del_a == 1 ? 5 : 4); + assert_scheduler(); + + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, data[_i].spi_del_a); + destroy_rekeyed(a, data[_i].spi_del_b); assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, data[_i].spi_a, data[_i].spi_b); + destroy_rekeyed(b, data[_i].spi_del_a); + destroy_rekeyed(b, data[_i].spi_del_b); + assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, data[_i].spi_a, data[_i].spi_b); /* child_rekey/child_updown */ assert_hook(); @@ -621,8 +853,10 @@ START_TEST(test_collision_delayed_request) exchange_test_helper->nonce_first_byte = data[_i].nonces[0]; initiate_rekey(a, 1); + assert_ipsec_sas_installed(a, 1, 2); exchange_test_helper->nonce_first_byte = data[_i].nonces[1]; initiate_rekey(b, 2); + assert_ipsec_sas_installed(b, 1, 2); /* delay the CREATE_CHILD_SA request from a to b */ msg = exchange_test_helper->sender->dequeue(exchange_test_helper->sender); @@ -634,14 +868,16 @@ START_TEST(test_collision_delayed_request) exchange_test_helper->nonce_first_byte = data[_i].nonces[2]; assert_hook_rekey(child_rekey, 1, 5); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYED); - assert_child_sa_state(a, 5, CHILD_INSTALLED); + assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(a, 1, 2, 5); assert_hook(); /* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */ assert_hook_rekey(child_rekey, 2, 4); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_DELETING); - assert_child_sa_state(b, 4, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5); assert_hook(); /* we don't expect this hook to get called anymore */ @@ -650,25 +886,43 @@ START_TEST(test_collision_delayed_request) /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> (delayed) */ assert_single_notify(OUT, TEMPORARY_FAILURE); exchange_test_helper->process_message(exchange_test_helper, b, msg); - assert_child_sa_state(b, 2, CHILD_DELETING); - assert_child_sa_state(b, 4, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 5, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 2); + assert_ipsec_sas_installed(a, 1, 4, 5); + assert_scheduler(); /* <-- CREATE_CHILD_SA { N(TEMP_FAIL) } */ assert_no_jobs_scheduled(); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 5, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 2); + assert_ipsec_sas_installed(a, 1, 4, 5); assert_scheduler(); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 4, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 2); + assert_ipsec_sas_installed(b, 2, 4, 5); + assert_scheduler(); + + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, 1); + assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, 4, 5); + destroy_rekeyed(b, 2); assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, 4, 5); /* child_rekey/child_updown */ assert_hook(); @@ -722,8 +976,10 @@ START_TEST(test_collision_delayed_request_more) exchange_test_helper->nonce_first_byte = data[_i].nonces[0]; initiate_rekey(a, 1); + assert_ipsec_sas_installed(a, 1, 2); exchange_test_helper->nonce_first_byte = data[_i].nonces[1]; initiate_rekey(b, 2); + assert_ipsec_sas_installed(b, 1, 2); /* delay the CREATE_CHILD_SA request from a to b */ msg = exchange_test_helper->sender->dequeue(exchange_test_helper->sender); @@ -735,40 +991,62 @@ START_TEST(test_collision_delayed_request_more) exchange_test_helper->nonce_first_byte = data[_i].nonces[2]; assert_hook_rekey(child_rekey, 1, 5); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYED); - assert_child_sa_state(a, 5, CHILD_INSTALLED); + assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(a, 1, 2, 5); assert_hook(); /* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */ assert_hook_rekey(child_rekey, 2, 4); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_DELETING); - assert_child_sa_state(b, 4, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5); assert_hook(); /* we don't expect this hook to get called anymore */ assert_hook_not_called(child_rekey); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 5, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 2); + assert_ipsec_sas_installed(a, 1, 4, 5); + assert_scheduler(); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 4, CHILD_INSTALLED); - assert_child_sa_count(b, 1); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 2); + assert_ipsec_sas_installed(b, 2, 4, 5); + assert_scheduler(); /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */ assert_single_notify(OUT, CHILD_SA_NOT_FOUND); exchange_test_helper->process_message(exchange_test_helper, b, msg); - assert_child_sa_state(b, 4, CHILD_INSTALLED); - assert_child_sa_count(b, 1); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 2); + assert_ipsec_sas_installed(b, 2, 4, 5); /* <-- CREATE_CHILD_SA { N(NO_CHILD_SA) } */ assert_no_jobs_scheduled(); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 5, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 2); + assert_ipsec_sas_installed(a, 1, 4, 5); assert_scheduler(); + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, 1); + assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, 4, 5); + destroy_rekeyed(b, 2); + assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, 4, 5); + /* child_rekey/child_updown */ assert_hook(); assert_hook(); @@ -842,13 +1120,13 @@ START_TEST(test_collision_ke_invalid) /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */ assert_hook_not_called(child_rekey); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_REKEYING); + assert_child_sa_state(b, 2, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(b, 1); assert_hook(); /* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */ assert_hook_not_called(child_rekey); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYING); + assert_child_sa_state(a, 1, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(a, 1); assert_hook(); @@ -857,7 +1135,7 @@ START_TEST(test_collision_ke_invalid) assert_hook_not_called(child_rekey); assert_single_notify(IN, INVALID_KE_PAYLOAD); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYING); + assert_child_sa_state(a, 1, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(a, 1); assert_hook(); /* CREATE_CHILD_SA { N(INVAL_KE) } --> */ @@ -865,7 +1143,7 @@ START_TEST(test_collision_ke_invalid) assert_hook_not_called(child_rekey); assert_single_notify(IN, INVALID_KE_PAYLOAD); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_REKEYING); + assert_child_sa_state(b, 2, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(b, 1); assert_hook(); @@ -873,15 +1151,15 @@ START_TEST(test_collision_ke_invalid) exchange_test_helper->nonce_first_byte = data[_i].nonces[2]; assert_hook_rekey(child_rekey, 2, 9); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_REKEYED); - assert_child_sa_state(b, 9, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 9, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); assert_hook(); /* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */ exchange_test_helper->nonce_first_byte = data[_i].nonces[3]; assert_hook_rekey(child_rekey, 1, 10); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYED); - assert_child_sa_state(a,10, CHILD_INSTALLED); + assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a,10, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); assert_hook(); /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */ @@ -891,49 +1169,99 @@ START_TEST(test_collision_ke_invalid) assert_hook_rekey(child_rekey, 1, data[_i].spi_a); exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_hook(); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED, + CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); } else { exchange_test_helper->process_message(exchange_test_helper, a, NULL); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_REGISTERED); } - assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING); - assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED); - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); /* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */ if (data[_i].spi_del_b == 2) { assert_hook_rekey(child_rekey, 2, data[_i].spi_b); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_hook(); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED, + CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); } else { exchange_test_helper->process_message(exchange_test_helper, b, NULL); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_REGISTERED); } - assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING); - assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); /* we don't expect this hook to get called anymore */ assert_hook_not_called(child_rekey); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); - assert_child_sa_count(b, 2); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 3); + assert_scheduler(); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING); - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); - assert_child_sa_count(a, 2); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 3); + assert_scheduler(); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 3); + assert_scheduler(); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, + CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 3); + assert_scheduler(); + + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, data[_i].spi_del_a); + destroy_rekeyed(a, data[_i].spi_del_b); + assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, data[_i].spi_a, data[_i].spi_b); + destroy_rekeyed(b, data[_i].spi_del_a); + destroy_rekeyed(b, data[_i].spi_del_b); assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, data[_i].spi_a, data[_i].spi_b); /* child_rekey/child_updown */ assert_hook(); @@ -1004,13 +1332,13 @@ START_TEST(test_collision_ke_invalid_delayed_retry) /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */ assert_hook_not_called(child_rekey); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_REKEYING); + assert_child_sa_state(b, 2, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(b, 1); assert_hook(); /* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */ assert_hook_not_called(child_rekey); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYING); + assert_child_sa_state(a, 1, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(a, 1); assert_hook(); @@ -1019,7 +1347,7 @@ START_TEST(test_collision_ke_invalid_delayed_retry) assert_hook_not_called(child_rekey); assert_single_notify(IN, INVALID_KE_PAYLOAD); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYING); + assert_child_sa_state(a, 1, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(a, 1); assert_hook(); /* CREATE_CHILD_SA { N(INVAL_KE) } --> */ @@ -1027,7 +1355,7 @@ START_TEST(test_collision_ke_invalid_delayed_retry) assert_hook_not_called(child_rekey); assert_single_notify(IN, INVALID_KE_PAYLOAD); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_REKEYING); + assert_child_sa_state(b, 2, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(b, 1); assert_hook(); @@ -1038,14 +1366,14 @@ START_TEST(test_collision_ke_invalid_delayed_retry) exchange_test_helper->nonce_first_byte = data[_i].nonces[2]; assert_hook_rekey(child_rekey, 1, 9); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 1, CHILD_REKEYED); - assert_child_sa_state(a, 9, CHILD_INSTALLED); + assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, 9, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); assert_hook(); /* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */ assert_hook_rekey(child_rekey, 2, 8); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 2, CHILD_DELETING); - assert_child_sa_state(b, 8, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 8, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); assert_hook(); /* we don't expect this hook to get called anymore */ @@ -1054,25 +1382,40 @@ START_TEST(test_collision_ke_invalid_delayed_retry) /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> (delayed) */ assert_single_notify(OUT, TEMPORARY_FAILURE); exchange_test_helper->process_message(exchange_test_helper, b, msg); - assert_child_sa_state(b, 2, CHILD_DELETING); - assert_child_sa_state(b, 8, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, 8, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); /* <-- INFORMATIONAL { D } */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 9, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, 9, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 2); + assert_scheduler(); /* <-- CREATE_CHILD_SA { N(TEMP_FAIL) } */ assert_no_jobs_scheduled(); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, 9, CHILD_INSTALLED); - assert_child_sa_count(a, 1); + assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(a, 9, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(a, 2); assert_scheduler(); /* INFORMATIONAL { D } --> */ + assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, 8, CHILD_INSTALLED); + assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE); + assert_child_sa_state(b, 8, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_count(b, 2); + assert_scheduler(); + + /* simulate the execution of the scheduled jobs */ + destroy_rekeyed(a, 1); + assert_child_sa_count(a, 1); + assert_ipsec_sas_installed(a, 8, 9); + destroy_rekeyed(b, 2); assert_child_sa_count(b, 1); + assert_ipsec_sas_installed(b, 8, 9); /* child_rekey/child_updown */ assert_hook(); @@ -1114,7 +1457,7 @@ START_TEST(test_collision_delete) } initiate_rekey(a, spi_a); call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE); - assert_child_sa_state(b, spi_b, CHILD_DELETING); + assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); /* this should never get called as there is no successful rekeying on * either side */ @@ -1129,7 +1472,7 @@ START_TEST(test_collision_delete) assert_notify(IN, REKEY_SA); assert_single_notify(OUT, TEMPORARY_FAILURE); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, spi_b, CHILD_DELETING); + assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); assert_hook(); /* RFC 7296, 2.25.1: If a peer receives a request to delete a CHILD_SA that @@ -1201,7 +1544,7 @@ START_TEST(test_collision_delete_drop_delete) } initiate_rekey(a, spi_a); call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE); - assert_child_sa_state(b, spi_b, CHILD_DELETING); + assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); /* this should never get called as there is no successful rekeying on * either side */ @@ -1216,7 +1559,7 @@ START_TEST(test_collision_delete_drop_delete) assert_notify(IN, REKEY_SA); assert_single_notify(OUT, TEMPORARY_FAILURE); exchange_test_helper->process_message(exchange_test_helper, b, NULL); - assert_child_sa_state(b, spi_b, CHILD_DELETING); + assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); assert_hook(); /* delay the DELETE request */ @@ -1227,7 +1570,7 @@ START_TEST(test_collision_delete_drop_delete) /* we expect a job to retry the rekeying is scheduled */ assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, spi_a, CHILD_INSTALLED); + assert_child_sa_state(a, spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); assert_scheduler(); assert_hook(); @@ -1286,7 +1629,7 @@ END_TEST } initiate_rekey(a, spi_a); call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE); - assert_child_sa_state(b, spi_b, CHILD_DELETING); + assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED); /* this should never get called as there is no successful rekeying on * either side */ @@ -1419,13 +1762,13 @@ START_TEST(test_collision_ike_rekey) /* <-- CREATE_CHILD_SA { SA, Ni, KEi } */ assert_single_notify(OUT, TEMPORARY_FAILURE); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, spi_a, CHILD_REKEYING); + assert_child_sa_state(a, spi_a, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); /* <-- CREATE_CHILD_SA { N(TEMP_FAIL) } */ /* we expect a job to retry the rekeying is scheduled */ assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); - assert_child_sa_state(a, spi_a, CHILD_INSTALLED); + assert_child_sa_state(a, spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); assert_scheduler(); /* CREATE_CHILD_SA { N(TEMP_FAIL) } --> */ diff --git a/src/libcharon/tests/utils/exchange_test_asserts.c b/src/libcharon/tests/utils/exchange_test_asserts.c index 2602b97b7..8042d0b63 100644 --- a/src/libcharon/tests/utils/exchange_test_asserts.c +++ b/src/libcharon/tests/utils/exchange_test_asserts.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Tobias Brunner + * Copyright (C) 2016-2017 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,6 +18,7 @@ #include <test_suite.h> #include "exchange_test_asserts.h" +#include "mock_ipsec.h" /* * Described in header @@ -180,3 +181,57 @@ bool exchange_test_asserts_message(listener_t *listener, ike_sa_t *ike_sa, } return TRUE; } + +/** + * Compare two SPIs + */ +static int spis_cmp(const void *a, const void *b) +{ + return *(const uint32_t*)a - *(const uint32_t*)b; +} + +/** + * Compare two SPIs to sort them + */ +static int spis_sort(const void *a, const void *b, void *data) +{ + return spis_cmp(a, b); +} + + +/* + * Described in header + */ +void exchange_test_asserts_ipsec_sas(ipsec_sas_assert_t *sas) +{ + enumerator_t *enumerator; + array_t *spis; + ike_sa_t *ike_sa; + uint32_t spi; + int i; + + spis = array_create(sizeof(uint32_t), 0); + for (i = 0; i < sas->count; i++) + { + array_insert(spis, ARRAY_TAIL, &sas->spis[i]); + } + array_sort(spis, spis_sort, NULL); + + enumerator = mock_ipsec_create_sa_enumerator(); + while (enumerator->enumerate(enumerator, &ike_sa, &spi)) + { + if (ike_sa == sas->ike_sa) + { + i = array_bsearch(spis, &spi, spis_cmp, NULL); + assert_listener_msg(i != -1, sas, "unexpected IPsec SA %.8x", spi); + array_remove(spis, i, NULL); + } + } + enumerator->destroy(enumerator); + for (i = 0; i < array_count(spis); i++) + { + array_get(spis, i, &spi); + assert_listener_msg(!spi, sas, "expected IPsec SA %.8x not found", spi); + } + array_destroy(spis); +} diff --git a/src/libcharon/tests/utils/exchange_test_asserts.h b/src/libcharon/tests/utils/exchange_test_asserts.h index 32afcc2e4..4d363edfd 100644 --- a/src/libcharon/tests/utils/exchange_test_asserts.h +++ b/src/libcharon/tests/utils/exchange_test_asserts.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Tobias Brunner + * Copyright (C) 2016-2017 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -14,7 +14,7 @@ */ /** - * Special assertions using listener_t. + * Special assertions using listener_t etc. * * @defgroup exchange_test_asserts exchange_test_asserts * @{ @ingroup test_utils_c @@ -28,6 +28,7 @@ typedef struct listener_hook_assert_t listener_hook_assert_t; typedef struct listener_message_assert_t listener_message_assert_t; typedef struct listener_message_rule_t listener_message_rule_t; +typedef struct ipsec_sas_assert_t ipsec_sas_assert_t; struct listener_hook_assert_t { @@ -340,4 +341,60 @@ bool exchange_test_asserts_message(listener_t *this, ike_sa_t *ike_sa, exchange_test_helper->add_listener(exchange_test_helper, &_listener.listener); \ }) +/** + * Data used to check IPsec SAs + */ +struct ipsec_sas_assert_t { + + /** + * Original source file + */ + const char *file; + + /** + * Source line + */ + int line; + + /** + * IKE_SA that installed the IPsec SAs + */ + ike_sa_t *ike_sa; + + /** + * SPIs to check + */ + uint32_t *spis; + + /** + * Number of SPIs for IPsec SAs to check + */ + int count; +}; + +/** + * Assert that all given IPsec SAs (and only these) are installed for the given + * IKE_SA. + */ +void exchange_test_asserts_ipsec_sas(ipsec_sas_assert_t *sas); + +/** + * Assert that the IPsec SAs with the given SPIs (and none other) are currently + * installed by the given IKE_SA. + * + * @param sa IKE_SA + * @param ... list of SPIs + */ +#define assert_ipsec_sas_installed(sa, ...) ({ \ + uint32_t _spis[] = { __VA_ARGS__ }; \ + ipsec_sas_assert_t _sas_assert = { \ + .file = __FILE__, \ + .line = __LINE__, \ + .ike_sa = sa, \ + .spis = _spis, \ + .count = countof(_spis), \ + }; \ + exchange_test_asserts_ipsec_sas(&_sas_assert); \ +}) + #endif /** EXCHANGE_TEST_ASSERTS_H_ @}*/ diff --git a/src/libcharon/tests/utils/mock_ipsec.c b/src/libcharon/tests/utils/mock_ipsec.c index d57a26a87..d6172f5bd 100644 --- a/src/libcharon/tests/utils/mock_ipsec.c +++ b/src/libcharon/tests/utils/mock_ipsec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Tobias Brunner + * Copyright (C) 2016-2017 Tobias Brunner * Copyright (C) 2008 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -16,6 +16,12 @@ #include "mock_ipsec.h" +#include <daemon.h> +#include <collections/hashtable.h> +#include <collections/array.h> + +#include <assert.h> + typedef struct private_kernel_ipsec_t private_kernel_ipsec_t; /** @@ -29,16 +35,80 @@ struct private_kernel_ipsec_t { kernel_ipsec_t public; /** + * Rekey listener + */ + listener_t listener; + + /** * Allocated SPI */ refcount_t spi; + + /** + * Installed SAs + */ + hashtable_t *sas; }; +/** + * Global instance + */ +static private_kernel_ipsec_t *instance; + +/** + * Data about installed IPsec SAs + */ +typedef struct { + /** + * SPI of the SA + */ + uint32_t spi; + + /** + * Associated IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * TRUE if this was an allocated SPI + */ + bool alloc; + +} entry_t; + +/** + * Hash an IPsec SA entry + */ +static u_int entry_hash(const void *key) +{ + entry_t *entry = (entry_t*)key; + return chunk_hash_inc(chunk_from_thing(entry->spi), + chunk_hash(chunk_from_thing(entry->ike_sa))); +} + +/** + * Compare an IPsec SA entry + */ +static bool entry_equals(const void *key, const void *other_key) +{ + entry_t *a = (entry_t*)key, *b = (entry_t*)other_key; + return a->spi == b->spi && a->ike_sa == b->ike_sa; +} + METHOD(kernel_ipsec_t, get_spi, status_t, private_kernel_ipsec_t *this, host_t *src, host_t *dst, uint8_t protocol, uint32_t *spi) { + entry_t *entry; + *spi = (uint32_t)ref_get(&this->spi); + INIT(entry, + .spi = *spi, + .ike_sa = charon->bus->get_sa(charon->bus), + .alloc = TRUE, + ); + entry = this->sas->put(this->sas, entry, entry); + assert(!entry); return SUCCESS; } @@ -52,6 +122,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t, private_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, kernel_ipsec_add_sa_t *data) { + entry_t *entry; + + INIT(entry, + .spi = id->spi, + .ike_sa = charon->bus->get_sa(charon->bus), + ); + if (data->inbound) + { + entry = this->sas->put(this->sas, entry, entry); + assert(entry && entry->alloc); + free(entry); + } + else + { + entry = this->sas->put(this->sas, entry, entry); + assert(!entry); + } return SUCCESS; } @@ -74,9 +161,47 @@ METHOD(kernel_ipsec_t, del_sa, status_t, private_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, kernel_ipsec_del_sa_t *data) { + entry_t *entry, lookup = { + .spi = id->spi, + .ike_sa = charon->bus->get_sa(charon->bus), + }; + + entry = this->sas->remove(this->sas, &lookup); + assert(entry); + free(entry); return SUCCESS; } +METHOD(listener_t, ike_rekey, bool, + listener_t *listener, ike_sa_t *old, ike_sa_t *new) +{ + enumerator_t *enumerator; + array_t *sas = NULL; + entry_t *entry; + + enumerator = instance->sas->create_enumerator(instance->sas); + while (enumerator->enumerate(enumerator, &entry, NULL)) + { + if (entry->ike_sa == old) + { + instance->sas->remove_at(instance->sas, enumerator); + array_insert_create(&sas, ARRAY_TAIL, entry); + } + } + enumerator->destroy(enumerator); + enumerator = array_create_enumerator(sas); + while (enumerator->enumerate(enumerator, &entry)) + { + array_remove_at(sas, enumerator); + entry->ike_sa = new; + entry = instance->sas->put(instance->sas, entry, entry); + assert(!entry); + } + enumerator->destroy(enumerator); + array_destroy(sas); + return TRUE; +} + METHOD(kernel_ipsec_t, add_policy, status_t, private_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id, kernel_ipsec_manage_policy_t *data) @@ -99,6 +224,14 @@ METHOD(kernel_ipsec_t, del_policy, status_t, return SUCCESS; } +METHOD(kernel_ipsec_t, destroy, void, + private_kernel_ipsec_t *this) +{ + charon->bus->remove_listener(charon->bus, &this->listener); + this->sas->destroy(this->sas); + free(this); +} + /* * Described in header */ @@ -121,8 +254,50 @@ kernel_ipsec_t *mock_ipsec_create() .flush_policies = (void*)return_failed, .bypass_socket = (void*)return_true, .enable_udp_decap = (void*)return_true, - .destroy = (void*)free, + .destroy = _destroy, + }, + .listener = { + .ike_rekey = _ike_rekey, }, + .sas = hashtable_create(entry_hash, entry_equals, 8), ); + + instance = this; + + charon->bus->add_listener(charon->bus, &this->listener); + return &this->public; } + + +CALLBACK(filter_sas, bool, + void *data, enumerator_t *orig, va_list args) +{ + entry_t *entry; + ike_sa_t **ike_sa; + uint32_t *spi; + + VA_ARGS_VGET(args, ike_sa, spi); + + while (orig->enumerate(orig, &entry, NULL)) + { + if (entry->alloc) + { + continue; + } + *ike_sa = entry->ike_sa; + *spi = entry->spi; + return TRUE; + } + return FALSE; +} + +/* + * Described in header + */ +enumerator_t *mock_ipsec_create_sa_enumerator() +{ + return enumerator_create_filter( + instance->sas->create_enumerator(instance->sas), + filter_sas, NULL, NULL); +} diff --git a/src/libcharon/tests/utils/mock_ipsec.h b/src/libcharon/tests/utils/mock_ipsec.h index cbf21524a..95038a561 100644 --- a/src/libcharon/tests/utils/mock_ipsec.h +++ b/src/libcharon/tests/utils/mock_ipsec.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Tobias Brunner + * Copyright (C) 2016-2017 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,7 +15,7 @@ /** * kernel_ipsec_t implementation used for exchange unit tests. Currently - * returns sequential SPIs, all other methods are noops. + * returns sequential SPIs, and keeps track of installed SAs. * * @defgroup mock_ipsec mock_ipsec * @{ @ingroup test_utils_c @@ -33,4 +33,11 @@ */ kernel_ipsec_t *mock_ipsec_create(); +/** + * Enumerate the installed SAs + * + * @return enumerator over (ike_sa_t*, uint32_t) + */ +enumerator_t *mock_ipsec_create_sa_enumerator(); + #endif /** MOCK_IPSEC_H_ @}*/ diff --git a/src/libcharon/tests/utils/sa_asserts.h b/src/libcharon/tests/utils/sa_asserts.h index 7afa3b55b..d23f724f1 100644 --- a/src/libcharon/tests/utils/sa_asserts.h +++ b/src/libcharon/tests/utils/sa_asserts.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Tobias Brunner + * Copyright (C) 2016-2017 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -82,13 +82,38 @@ }) /** + * Check if the CHILD_SA with the given SPI is in the expected state, optionally + * check the state of the outbound SA. + */ +#define assert_child_sa_state(...) VA_ARGS_DISPATCH(assert_child_sa_state, __VA_ARGS__)(__VA_ARGS__) + +/** * Check if the CHILD_SA with the given SPI is in the expected state. */ -#define assert_child_sa_state(ike_sa, spi, state) \ +#define assert_child_sa_state3(ike_sa, spi, state) \ +({ \ + typeof(ike_sa) _sa = ike_sa; \ + typeof(spi) _spi = spi; \ + typeof(state) _state = state; \ + child_sa_t *_child = _sa->get_child_sa(_sa, PROTO_ESP, _spi, TRUE) ?: \ + _sa->get_child_sa(_sa, PROTO_ESP, _spi, FALSE); \ + test_assert_msg(_child, "CHILD_SA with SPI %.8x does not exist", \ + ntohl(_spi)); \ + test_assert_msg(_state == _child->get_state(_child), "%N != %N", \ + child_sa_state_names, _state, \ + child_sa_state_names, _child->get_state(_child)); \ +}) + +/** + * Check if the outbound SA of a CHILD_SA with the given SPI is in the + * expected state. + */ +#define assert_child_sa_state4(ike_sa, spi, state, outbound) \ ({ \ typeof(ike_sa) _sa = ike_sa; \ typeof(spi) _spi = spi; \ typeof(state) _state = state; \ + typeof(outbound) _outbound = outbound; \ child_sa_t *_child = _sa->get_child_sa(_sa, PROTO_ESP, _spi, TRUE) ?: \ _sa->get_child_sa(_sa, PROTO_ESP, _spi, FALSE); \ test_assert_msg(_child, "CHILD_SA with SPI %.8x does not exist", \ @@ -96,6 +121,9 @@ test_assert_msg(_state == _child->get_state(_child), "%N != %N", \ child_sa_state_names, _state, \ child_sa_state_names, _child->get_state(_child)); \ + test_assert_msg(_outbound == _child->get_outbound_state(_child), "%N != %N", \ + child_sa_outbound_state_names, _outbound, \ + child_sa_outbound_state_names, _child->get_outbound_state(_child)); \ }) /** |