diff options
| author | Yves-Alexis Perez <corsac@debian.org> | 2013-08-25 15:37:27 +0200 | 
|---|---|---|
| committer | Yves-Alexis Perez <corsac@debian.org> | 2013-08-25 15:37:27 +0200 | 
| commit | c7307e752d8f47c68f834e22ee2ce0a14a70e695 (patch) | |
| tree | fbb442a20ab54aad511b46a070e65b8d09c22791 /src/libhydra/plugins/kernel_netlink | |
| parent | f74c6d77c3efb529e7403eeef0613c061eb895b3 (diff) | |
| parent | 6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349 (diff) | |
| download | vyos-strongswan-c7307e752d8f47c68f834e22ee2ce0a14a70e695.tar.gz vyos-strongswan-c7307e752d8f47c68f834e22ee2ce0a14a70e695.zip | |
Merge tag 'upstream/5.1.0'
Upstream version 5.1.0
Diffstat (limited to 'src/libhydra/plugins/kernel_netlink')
5 files changed, 169 insertions, 93 deletions
| diff --git a/src/libhydra/plugins/kernel_netlink/Makefile.am b/src/libhydra/plugins/kernel_netlink/Makefile.am index 1ad379421..ad573523e 100644 --- a/src/libhydra/plugins/kernel_netlink/Makefile.am +++ b/src/libhydra/plugins/kernel_netlink/Makefile.am @@ -1,10 +1,12 @@ +AM_CPPFLAGS = \ +	-I${linux_headers} \ +	-I$(top_srcdir)/src/libstrongswan \ +	-I$(top_srcdir)/src/libhydra \ +	-DROUTING_TABLE=${routing_table} \ +	-DROUTING_TABLE_PRIO=${routing_table_prio} -INCLUDES = -I${linux_headers} -I$(top_srcdir)/src/libstrongswan \ -	-I$(top_srcdir)/src/libhydra - -AM_CFLAGS = -rdynamic \ --DROUTING_TABLE=${routing_table} \ --DROUTING_TABLE_PRIO=${routing_table_prio} +AM_CFLAGS = \ +	-rdynamic  if MONOLITHIC  noinst_LTLIBRARIES = libstrongswan-kernel-netlink.la diff --git a/src/libhydra/plugins/kernel_netlink/Makefile.in b/src/libhydra/plugins/kernel_netlink/Makefile.in index 9702010bb..9cb988c8d 100644 --- a/src/libhydra/plugins/kernel_netlink/Makefile.in +++ b/src/libhydra/plugins/kernel_netlink/Makefile.in @@ -62,7 +62,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \  	$(top_srcdir)/m4/macros/with.m4 \  	$(top_srcdir)/m4/macros/enable-disable.m4 \  	$(top_srcdir)/m4/macros/add-plugin.m4 \ -	$(top_srcdir)/configure.in +	$(top_srcdir)/configure.ac  am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \  	$(ACLOCAL_M4)  mkinstalldirs = $(install_sh) -d @@ -104,7 +104,10 @@ am_libstrongswan_kernel_netlink_la_OBJECTS = kernel_netlink_plugin.lo \  	kernel_netlink_shared.lo  libstrongswan_kernel_netlink_la_OBJECTS =  \  	$(am_libstrongswan_kernel_netlink_la_OBJECTS) -libstrongswan_kernel_netlink_la_LINK = $(LIBTOOL) --tag=CC \ +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libstrongswan_kernel_netlink_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \  	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \  	$(AM_CFLAGS) $(CFLAGS) \  	$(libstrongswan_kernel_netlink_la_LDFLAGS) $(LDFLAGS) -o $@ @@ -117,13 +120,26 @@ am__depfiles_maybe = depfiles  am__mv = mv -f  COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \  	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ -	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ -	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ +	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ +	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +	$(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo "  CC    " $@; +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @  CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ -	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ -	$(LDFLAGS) -o $@ +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ +	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ +	$(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo "  CCLD  " $@; +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo "  GEN   " $@;  SOURCES = $(libstrongswan_kernel_netlink_la_SOURCES)  DIST_SOURCES = $(libstrongswan_kernel_netlink_la_SOURCES)  am__can_run_installinfo = \ @@ -137,6 +153,7 @@ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)  ACLOCAL = @ACLOCAL@  ALLOCA = @ALLOCA@  AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@  AR = @AR@  AUTOCONF = @AUTOCONF@  AUTOHEADER = @AUTOHEADER@ @@ -149,6 +166,8 @@ CCDEPMODE = @CCDEPMODE@  CFLAGS = @CFLAGS@  CHECK_CFLAGS = @CHECK_CFLAGS@  CHECK_LIBS = @CHECK_LIBS@ +COVERAGE_CFLAGS = @COVERAGE_CFLAGS@ +COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@  CPP = @CPP@  CPPFLAGS = @CPPFLAGS@  CYGPATH_W = @CYGPATH_W@ @@ -164,6 +183,7 @@ ECHO_T = @ECHO_T@  EGREP = @EGREP@  EXEEXT = @EXEEXT@  FGREP = @FGREP@ +GENHTML = @GENHTML@  GPERF = @GPERF@  GPRBUILD = @GPRBUILD@  GREP = @GREP@ @@ -172,6 +192,7 @@ INSTALL_DATA = @INSTALL_DATA@  INSTALL_PROGRAM = @INSTALL_PROGRAM@  INSTALL_SCRIPT = @INSTALL_SCRIPT@  INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCOV = @LCOV@  LD = @LD@  LDFLAGS = @LDFLAGS@  LEX = @LEX@ @@ -218,6 +239,7 @@ SET_MAKE = @SET_MAKE@  SHELL = @SHELL@  SOCKLIB = @SOCKLIB@  STRIP = @STRIP@ +UNWINDLIB = @UNWINDLIB@  VERSION = @VERSION@  YACC = @YACC@  YFLAGS = @YFLAGS@ @@ -246,6 +268,7 @@ charon_natt_port = @charon_natt_port@  charon_plugins = @charon_plugins@  charon_udp_port = @charon_udp_port@  clearsilver_LIBS = @clearsilver_LIBS@ +cmd_plugins = @cmd_plugins@  datadir = @datadir@  datarootdir = @datarootdir@  dbusservicedir = @dbusservicedir@ @@ -323,12 +346,15 @@ top_srcdir = @top_srcdir@  urandom_device = @urandom_device@  xml_CFLAGS = @xml_CFLAGS@  xml_LIBS = @xml_LIBS@ -INCLUDES = -I${linux_headers} -I$(top_srcdir)/src/libstrongswan \ -	-I$(top_srcdir)/src/libhydra +AM_CPPFLAGS = \ +	-I${linux_headers} \ +	-I$(top_srcdir)/src/libstrongswan \ +	-I$(top_srcdir)/src/libhydra \ +	-DROUTING_TABLE=${routing_table} \ +	-DROUTING_TABLE_PRIO=${routing_table_prio} -AM_CFLAGS = -rdynamic \ --DROUTING_TABLE=${routing_table} \ --DROUTING_TABLE_PRIO=${routing_table_prio} +AM_CFLAGS = \ +	-rdynamic  @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-kernel-netlink.la  @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-kernel-netlink.la @@ -415,7 +441,7 @@ clean-pluginLTLIBRARIES:  	  rm -f "$${dir}/so_locations"; \  	done  libstrongswan-kernel-netlink.la: $(libstrongswan_kernel_netlink_la_OBJECTS) $(libstrongswan_kernel_netlink_la_DEPENDENCIES) $(EXTRA_libstrongswan_kernel_netlink_la_DEPENDENCIES)  -	$(libstrongswan_kernel_netlink_la_LINK) $(am_libstrongswan_kernel_netlink_la_rpath) $(libstrongswan_kernel_netlink_la_OBJECTS) $(libstrongswan_kernel_netlink_la_LIBADD) $(LIBS) +	$(AM_V_CCLD)$(libstrongswan_kernel_netlink_la_LINK) $(am_libstrongswan_kernel_netlink_la_rpath) $(libstrongswan_kernel_netlink_la_OBJECTS) $(libstrongswan_kernel_netlink_la_LIBADD) $(LIBS)  mostlyclean-compile:  	-rm -f *.$(OBJEXT) @@ -429,25 +455,25 @@ distclean-compile:  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_netlink_shared.Plo@am__quote@  .c.o: -@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@	$(COMPILE) -c $< +@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<  .c.obj: -@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`  .c.lo: -@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<  mostlyclean-libtool:  	-rm -f *.lo diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index 9b4ade533..b34fa149c 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -37,11 +37,9 @@  #include <hydra.h>  #include <utils/debug.h> -#include <threading/thread.h>  #include <threading/mutex.h>  #include <collections/hashtable.h>  #include <collections/linked_list.h> -#include <processing/jobs/callback_job.h>  /** Required for Linux 2.6.26 kernel and later */  #ifndef XFRM_STATE_AF_UNSPEC @@ -558,6 +556,9 @@ struct policy_entry_t {  	/** List of SAs this policy is used by, ordered by priority */  	linked_list_t *used_by; + +	/** reqid for this policy */ +	u_int32_t reqid;  };  /** @@ -969,40 +970,37 @@ static void process_mapping(private_kernel_netlink_ipsec_t *this,  /**   * Receives events from kernel   */ -static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this) +static bool receive_events(private_kernel_netlink_ipsec_t *this, int fd, +						   watcher_event_t event)  {  	char response[1024];  	struct nlmsghdr *hdr = (struct nlmsghdr*)response;  	struct sockaddr_nl addr;  	socklen_t addr_len = sizeof(addr);  	int len; -	bool oldstate; - -	oldstate = thread_cancelability(TRUE); -	len = recvfrom(this->socket_xfrm_events, response, sizeof(response), 0, -				   (struct sockaddr*)&addr, &addr_len); -	thread_cancelability(oldstate); +	len = recvfrom(this->socket_xfrm_events, response, sizeof(response), +				   MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len);  	if (len < 0)  	{  		switch (errno)  		{  			case EINTR:  				/* interrupted, try again */ -				return JOB_REQUEUE_DIRECT; +				return TRUE;  			case EAGAIN:  				/* no data ready, select again */ -				return JOB_REQUEUE_DIRECT; +				return TRUE;  			default:  				DBG1(DBG_KNL, "unable to receive from xfrm event socket");  				sleep(1); -				return JOB_REQUEUE_FAIR; +				return TRUE;  		}  	}  	if (addr.nl_pid != 0)  	{	/* not from kernel. not interested, try another one */ -		return JOB_REQUEUE_DIRECT; +		return TRUE;  	}  	while (NLMSG_OK(hdr, len)) @@ -1028,7 +1026,7 @@ static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this)  		}  		hdr = NLMSG_NEXT(hdr, len);  	} -	return JOB_REQUEUE_DIRECT; +	return TRUE;  }  METHOD(kernel_ipsec_t, get_features, kernel_feature_t, @@ -1170,7 +1168,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,  	u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,  	u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,  	u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, -	u_int16_t cpi, bool encap, bool esn, bool inbound, +	u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,  	traffic_selector_t* src_ts, traffic_selector_t* dst_ts)  {  	netlink_buf_t request; @@ -1187,7 +1185,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,  		lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};  		add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, mark,  			   tfc, &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, -			   chunk_empty, mode, ipcomp, 0, FALSE, FALSE, inbound, NULL, NULL); +			   chunk_empty, mode, ipcomp, 0, initiator, FALSE, FALSE, inbound, +			   NULL, NULL);  		ipcomp = IPCOMP_NONE;  		/* use transport mode ESP SA, IPComp uses tunnel mode */  		mode = MODE_TRANSPORT; @@ -1220,6 +1219,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t,  			if(src_ts && dst_ts)  			{  				sa->sel = ts2selector(src_ts, dst_ts); +				/* don't install proto/port on SA. This would break +				 * potential secondary SAs for the same address using a +				 * different prot/port. */ +				sa->sel.proto = 0; +				sa->sel.dport = sa->sel.dport_mask = 0; +				sa->sel.sport = sa->sel.sport_mask = 0;  			}  			break;  		default: @@ -1595,7 +1600,7 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this,  METHOD(kernel_ipsec_t, query_sa, status_t,  	private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,  	u_int32_t spi, u_int8_t protocol, mark_t mark, -	u_int64_t *bytes, u_int64_t *packets) +	u_int64_t *bytes, u_int64_t *packets, u_int32_t *time)  {  	netlink_buf_t request;  	struct nlmsghdr *out = NULL, *hdr; @@ -1680,6 +1685,12 @@ METHOD(kernel_ipsec_t, query_sa, status_t,  		{  			*packets = sa->curlft.packets;  		} +		if (time) +		{	/* curlft contains an "use" time, but that contains a timestamp +			 * of the first use, not the last. Last use time must be queried +			 * on the policy on Linux */ +			*time = 0; +		}  		status = SUCCESS;  	}  	memwipe(out, len); @@ -2041,7 +2052,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,  			{  				continue;  			} -			tmpl->reqid = ipsec->cfg.reqid; +			tmpl->reqid = policy->reqid;  			tmpl->id.proto = protos[i].proto;  			tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;  			tmpl->mode = mode2kernel(proto_mode); @@ -2049,7 +2060,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,  							 policy->direction != POLICY_OUT;  			tmpl->family = ipsec->src->get_family(ipsec->src); -			if (proto_mode == MODE_TUNNEL) +			if (proto_mode == MODE_TUNNEL || proto_mode == MODE_BEET)  			{	/* only for tunnel mode */  				host2xfrm(ipsec->src, &tmpl->saddr);  				host2xfrm(ipsec->dst, &tmpl->id.daddr); @@ -2102,7 +2113,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,  		);  		if (hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface, -				fwd->dst_ts, &route->src_ip) == SUCCESS) +				fwd->dst_ts, &route->src_ip, NULL) == SUCCESS)  		{  			/* get the nexthop to src (src as we are in POLICY_FWD) */  			route->gateway = hydra->kernel_interface->get_nexthop( @@ -2197,6 +2208,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,  		.sel = ts2selector(src_ts, dst_ts),  		.mark = mark.value & mark.mask,  		.direction = direction, +		.reqid = sa->reqid,  	);  	/* find the policy, which matches EXACTLY */ @@ -2204,6 +2216,16 @@ METHOD(kernel_ipsec_t, add_policy, status_t,  	current = this->policies->get(this->policies, policy);  	if (current)  	{ +		if (current->reqid != sa->reqid) +		{ +			DBG1(DBG_CFG, "unable to install policy %R === %R %N (mark " +				 "%u/0x%08x) for reqid %u, the same policy for reqid %u exists", +				 src_ts, dst_ts, policy_dir_names, direction, +				 mark.value, mark.mask, sa->reqid, current->reqid); +			policy_entry_destroy(this, policy); +			this->mutex->unlock(this->mutex); +			return INVALID_STATE; +		}  		/* use existing policy */  		DBG2(DBG_KNL, "policy %R === %R %N  (mark %u/0x%08x) "  					  "already exists, increasing refcount", @@ -2375,7 +2397,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,  	/* find the policy */  	this->mutex->lock(this->mutex);  	current = this->policies->get(this->policies, &policy); -	if (!current) +	if (!current || current->reqid != reqid)  	{  		if (mark.value)  		{ @@ -2398,8 +2420,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,  		enumerator = current->used_by->create_enumerator(current->used_by);  		while (enumerator->enumerate(enumerator, (void**)&mapping))  		{ -			if (reqid == mapping->sa->cfg.reqid && -				priority == mapping->priority) +			if (priority == mapping->priority)  			{  				current->used_by->remove_at(current->used_by, enumerator);  				policy_sa_destroy(mapping, &direction, this); @@ -2579,6 +2600,7 @@ METHOD(kernel_ipsec_t, destroy, void,  	if (this->socket_xfrm_events > 0)  	{ +		lib->watcher->remove(lib->watcher, this->socket_xfrm_events);  		close(this->socket_xfrm_events);  	}  	DESTROY_IF(this->socket_xfrm); @@ -2638,13 +2660,7 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()  	this->replay_bmp = (this->replay_window + sizeof(u_int32_t) * 8 - 1) /  													(sizeof(u_int32_t) * 8); -	if (streq(hydra->daemon, "pluto")) -	{	/* no routes for pluto, they are installed via updown script */ -		this->install_routes = FALSE; -		/* no policy history for pluto */ -		this->policy_history = FALSE; -	} -	else if (streq(hydra->daemon, "starter")) +	if (streq(hydra->daemon, "starter"))  	{	/* starter has no threads, so we do not register for kernel events */  		register_for_events = FALSE;  	} @@ -2687,10 +2703,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()  			destroy(this);  			return NULL;  		} -		lib->processor->queue_job(lib->processor, -			(job_t*)callback_job_create_with_prio( -					(callback_job_cb_t)receive_events, this, NULL, -					(callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); +		lib->watcher->add(lib->watcher, this->socket_xfrm_events, WATCHER_READ, +						  (watcher_cb_t)receive_events, this);  	}  	return &this->public; diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c index 3e0725a35..e129ab131 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c @@ -1,5 +1,5 @@  /* - * Copyright (C) 2008-2012 Tobias Brunner + * Copyright (C) 2008-2013 Tobias Brunner   * Copyright (C) 2005-2008 Martin Willi   * Hochschule fuer Technik Rapperswil   * @@ -50,7 +50,6 @@  #include <hydra.h>  #include <utils/debug.h> -#include <threading/thread.h>  #include <threading/mutex.h>  #include <threading/rwlock.h>  #include <threading/rwlock_condvar.h> @@ -68,6 +67,14 @@  /** maximum recursion when searching for addresses in get_route() */  #define MAX_ROUTE_RECURSION 2 +#ifndef ROUTING_TABLE +#define ROUTING_TABLE 0 +#endif + +#ifndef ROUTING_TABLE_PRIO +#define ROUTING_TABLE_PRIO 0 +#endif +  typedef struct addr_entry_t addr_entry_t;  /** @@ -257,7 +264,7 @@ static route_entry_t *route_entry_clone(route_entry_t *this)  	INIT(route,  		.if_name = strdup(this->if_name),  		.src_ip = this->src_ip->clone(this->src_ip), -		.gateway = this->gateway->clone(this->gateway), +		.gateway = this->gateway ? this->gateway->clone(this->gateway) : NULL,  		.dst_net = chunk_clone(this->dst_net),  		.prefixlen = this->prefixlen,  	); @@ -290,10 +297,14 @@ static u_int route_entry_hash(route_entry_t *this)   */  static bool route_entry_equals(route_entry_t *a, route_entry_t *b)  { -	return a->if_name && b->if_name && streq(a->if_name, b->if_name) && -		   a->src_ip->ip_equals(a->src_ip, b->src_ip) && -		   a->gateway->ip_equals(a->gateway, b->gateway) && -		   chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen; +	if (a->if_name && b->if_name && streq(a->if_name, b->if_name) && +		a->src_ip->ip_equals(a->src_ip, b->src_ip) && +		chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen) +	{ +		return (!a->gateway && !b->gateway) || (a->gateway && b->gateway && +					a->gateway->ip_equals(a->gateway, b->gateway)); +	} +	return FALSE;  }  typedef struct net_change_t net_change_t; @@ -428,6 +439,11 @@ struct private_kernel_netlink_net_t {  	bool process_route;  	/** +	 * whether to trigger roam events +	 */ +	bool roam_events; + +	/**  	 * whether to actually install virtual IPs  	 */  	bool install_virtual_ip; @@ -695,6 +711,11 @@ static void fire_roam_event(private_kernel_netlink_net_t *this, bool address)  	timeval_t now;  	job_t *job; +	if (!this->roam_events) +	{ +		return; +	} +  	time_monotonic(&now);  	this->roam_lock->lock(this->roam_lock);  	if (!timercmp(&now, &this->next_roam, >)) @@ -1057,40 +1078,37 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h  /**   * Receives events from kernel   */ -static job_requeue_t receive_events(private_kernel_netlink_net_t *this) +static bool receive_events(private_kernel_netlink_net_t *this, int fd, +						   watcher_event_t event)  {  	char response[1024];  	struct nlmsghdr *hdr = (struct nlmsghdr*)response;  	struct sockaddr_nl addr;  	socklen_t addr_len = sizeof(addr);  	int len; -	bool oldstate; - -	oldstate = thread_cancelability(TRUE); -	len = recvfrom(this->socket_events, response, sizeof(response), 0, -				   (struct sockaddr*)&addr, &addr_len); -	thread_cancelability(oldstate); +	len = recvfrom(this->socket_events, response, sizeof(response), +				   MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len);  	if (len < 0)  	{  		switch (errno)  		{  			case EINTR:  				/* interrupted, try again */ -				return JOB_REQUEUE_DIRECT; +				return TRUE;  			case EAGAIN:  				/* no data ready, select again */ -				return JOB_REQUEUE_DIRECT; +				return TRUE;  			default:  				DBG1(DBG_KNL, "unable to receive from rt event socket");  				sleep(1); -				return JOB_REQUEUE_FAIR; +				return TRUE;  		}  	}  	if (addr.nl_pid != 0)  	{	/* not from kernel. not interested, try another one */ -		return JOB_REQUEUE_DIRECT; +		return TRUE;  	}  	while (NLMSG_OK(hdr, len)) @@ -1118,7 +1136,7 @@ static job_requeue_t receive_events(private_kernel_netlink_net_t *this)  		}  		hdr = NLMSG_NEXT(hdr, len);  	} -	return JOB_REQUEUE_DIRECT; +	return TRUE;  }  /** enumerator over addresses */ @@ -1147,6 +1165,10 @@ static bool filter_addresses(address_enumerator_t *data,  	{	/* 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; @@ -1191,9 +1213,12 @@ static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,  METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,  	private_kernel_netlink_net_t *this, kernel_address_type_t which)  { -	address_enumerator_t *data = malloc_thing(address_enumerator_t); -	data->this = this; -	data->which = which; +	address_enumerator_t *data; + +	INIT(data, +		.this = this, +		.which = which, +	);  	this->lock->read_lock(this->lock);  	return enumerator_create_nested( @@ -1237,7 +1262,7 @@ METHOD(kernel_net_t, get_interface_name, bool,  		if (name)  		{  			*name = strdup(entry->iface->ifname); -			DBG2(DBG_KNL, "virtual %H is on interface %s", ip, *name); +			DBG2(DBG_KNL, "virtual IP %H is on interface %s", ip, *name);  		}  		this->lock->unlock(this->lock);  		return TRUE; @@ -2146,6 +2171,7 @@ METHOD(kernel_net_t, destroy, void,  	}  	if (this->socket_events > 0)  	{ +		lib->watcher->remove(lib->watcher, this->socket_events);  		close(this->socket_events);  	}  	enumerator = this->routes->create_enumerator(this->routes); @@ -2227,6 +2253,8 @@ kernel_netlink_net_t *kernel_netlink_net_create()  				"%s.install_virtual_ip", TRUE, hydra->daemon),  		.install_virtual_ip_on = lib->settings->get_str(lib->settings,  				"%s.install_virtual_ip_on", NULL, hydra->daemon), +		.roam_events = lib->settings->get_bool(lib->settings, +				"%s.plugins.kernel-netlink.roam_events", TRUE, hydra->daemon),  	);  	timerclear(&this->last_route_reinstall);  	timerclear(&this->next_roam); @@ -2283,10 +2311,8 @@ kernel_netlink_net_t *kernel_netlink_net_create()  			return NULL;  		} -		lib->processor->queue_job(lib->processor, -			(job_t*)callback_job_create_with_prio( -					(callback_job_cb_t)receive_events, this, NULL, -					(callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); +		lib->watcher->add(lib->watcher, this->socket_events, WATCHER_READ, +						  (watcher_cb_t)receive_events, this);  	}  	if (init_address_list(this) != SUCCESS) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c index 0eb00dadf..8d5a0d5e8 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c @@ -65,6 +65,14 @@ plugin_t *kernel_netlink_plugin_create()  {  	private_kernel_netlink_plugin_t *this; +	if (!lib->caps->keep(lib->caps, CAP_NET_ADMIN)) +	{	/* required to bind/use XFRM sockets / create/modify routing tables, but +		 * not if only the read-only parts of kernel-netlink-net are used, so +		 * we don't fail here */ +		DBG1(DBG_KNL, "kernel-netlink plugin might require CAP_NET_ADMIN " +			 "capability"); +	} +  	INIT(this,  		.public = {  			.plugin = { | 
