summaryrefslogtreecommitdiff
path: root/src/libhydra
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
committerYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
commitb34738ed08c2227300d554b139e2495ca5da97d6 (patch)
tree62f33b52820f2e49f0e53c0f8c636312037c8054 /src/libhydra
parent0a9d51a49042a68daa15b0c74a2b7f152f52606b (diff)
downloadvyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.tar.gz
vyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.zip
Imported Upstream version 4.6.4
Diffstat (limited to 'src/libhydra')
-rw-r--r--src/libhydra/Android.mk4
-rw-r--r--src/libhydra/Makefile.am4
-rw-r--r--src/libhydra/Makefile.in77
-rw-r--r--src/libhydra/attributes/attribute_manager.c124
-rw-r--r--src/libhydra/attributes/attributes.c58
-rw-r--r--src/libhydra/attributes/attributes.h1
-rw-r--r--src/libhydra/kernel/kernel_interface.c60
-rw-r--r--src/libhydra/kernel/kernel_interface.h28
-rw-r--r--src/libhydra/kernel/kernel_ipsec.c24
-rw-r--r--src/libhydra/kernel/kernel_ipsec.h60
-rw-r--r--src/libhydra/kernel/kernel_listener.h2
-rw-r--r--src/libhydra/kernel/kernel_net.c37
-rw-r--r--src/libhydra/kernel/kernel_net.h15
-rw-r--r--src/libhydra/plugins/attr/Makefile.in7
-rw-r--r--src/libhydra/plugins/attr_sql/Makefile.in7
-rw-r--r--src/libhydra/plugins/attr_sql/pool.c8
-rw-r--r--src/libhydra/plugins/attr_sql/sql_attribute.c56
-rw-r--r--src/libhydra/plugins/kernel_klips/Makefile.in7
-rw-r--r--src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c27
-rw-r--r--src/libhydra/plugins/kernel_klips/kernel_klips_plugin.c17
-rw-r--r--src/libhydra/plugins/kernel_netlink/Makefile.in7
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c1035
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c41
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c23
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c41
-rw-r--r--src/libhydra/plugins/kernel_pfkey/Makefile.in7
-rw-r--r--src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c917
-rw-r--r--src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c17
-rw-r--r--src/libhydra/plugins/kernel_pfroute/Makefile.in7
-rw-r--r--src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c4
-rw-r--r--src/libhydra/plugins/kernel_pfroute/kernel_pfroute_plugin.c17
-rw-r--r--src/libhydra/plugins/resolve/Makefile.in7
-rw-r--r--src/libhydra/plugins/resolve/resolve_handler.c245
-rw-r--r--src/libhydra/plugins/resolve/resolve_plugin.c2
34 files changed, 2120 insertions, 873 deletions
diff --git a/src/libhydra/Android.mk b/src/libhydra/Android.mk
index 2418e76ad..075f8dbcb 100644
--- a/src/libhydra/Android.mk
+++ b/src/libhydra/Android.mk
@@ -10,7 +10,7 @@ attributes/attribute_manager.c attributes/attribute_manager.h \
attributes/mem_pool.c attributes/mem_pool.h \
kernel/kernel_interface.c kernel/kernel_interface.h \
kernel/kernel_ipsec.c kernel/kernel_ipsec.h \
-kernel/kernel_net.h \
+kernel/kernel_net.c kernel/kernel_net.h \
kernel/kernel_listener.h
# adding the plugin source files
@@ -32,6 +32,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libhydra
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/libhydra/Makefile.am b/src/libhydra/Makefile.am
index d0698d0f5..1c7b3ba43 100644
--- a/src/libhydra/Makefile.am
+++ b/src/libhydra/Makefile.am
@@ -1,4 +1,4 @@
-lib_LTLIBRARIES = libhydra.la
+ipseclib_LTLIBRARIES = libhydra.la
libhydra_la_SOURCES = \
hydra.c hydra.h \
@@ -8,7 +8,7 @@ attributes/attribute_manager.c attributes/attribute_manager.h \
attributes/mem_pool.c attributes/mem_pool.h \
kernel/kernel_interface.c kernel/kernel_interface.h \
kernel/kernel_ipsec.c kernel/kernel_ipsec.h \
-kernel/kernel_net.h \
+kernel/kernel_net.c kernel/kernel_net.h \
kernel/kernel_listener.h
libhydra_la_LIBADD =
diff --git a/src/libhydra/Makefile.in b/src/libhydra/Makefile.in
index 08c73b5e3..f452719dd 100644
--- a/src/libhydra/Makefile.in
+++ b/src/libhydra/Makefile.in
@@ -86,13 +86,13 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__installdirs = "$(DESTDIR)$(libdir)"
-LTLIBRARIES = $(lib_LTLIBRARIES)
+am__installdirs = "$(DESTDIR)$(ipseclibdir)"
+LTLIBRARIES = $(ipseclib_LTLIBRARIES)
libhydra_la_DEPENDENCIES = $(am__append_2) $(am__append_4) \
$(am__append_6) $(am__append_8) $(am__append_10) \
$(am__append_12) $(am__append_14)
am_libhydra_la_OBJECTS = hydra.lo attributes.lo attribute_manager.lo \
- mem_pool.lo kernel_interface.lo kernel_ipsec.lo
+ mem_pool.lo kernel_interface.lo kernel_ipsec.lo kernel_net.lo
libhydra_la_OBJECTS = $(am_libhydra_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
@@ -243,6 +243,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -251,6 +254,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -267,11 +271,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -315,6 +321,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
@@ -325,7 +332,7 @@ top_srcdir = @top_srcdir@
urandom_device = @urandom_device@
xml_CFLAGS = @xml_CFLAGS@
xml_LIBS = @xml_LIBS@
-lib_LTLIBRARIES = libhydra.la
+ipseclib_LTLIBRARIES = libhydra.la
libhydra_la_SOURCES = \
hydra.c hydra.h \
attributes/attributes.c attributes/attributes.h \
@@ -334,7 +341,7 @@ attributes/attribute_manager.c attributes/attribute_manager.h \
attributes/mem_pool.c attributes/mem_pool.h \
kernel/kernel_interface.c kernel/kernel_interface.h \
kernel/kernel_ipsec.c kernel/kernel_ipsec.h \
-kernel/kernel_net.h \
+kernel/kernel_net.c kernel/kernel_net.h \
kernel/kernel_listener.h
libhydra_la_LIBADD = $(am__append_2) $(am__append_4) $(am__append_6) \
@@ -392,39 +399,39 @@ $(top_srcdir)/configure: $(am__configure_deps)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
-install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES)
@$(NORMAL_INSTALL)
- test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
- @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ test -z "$(ipseclibdir)" || $(MKDIR_P) "$(DESTDIR)$(ipseclibdir)"
+ @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
- echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
- $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(ipseclibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \
}
-uninstall-libLTLIBRARIES:
+uninstall-ipseclibLTLIBRARIES:
@$(NORMAL_UNINSTALL)
- @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
- echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
- $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(ipseclibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \
done
-clean-libLTLIBRARIES:
- -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
- @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+clean-ipseclibLTLIBRARIES:
+ -test -z "$(ipseclib_LTLIBRARIES)" || rm -f $(ipseclib_LTLIBRARIES)
+ @list='$(ipseclib_LTLIBRARIES)'; for p in $$list; do \
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
test "$$dir" != "$$p" || dir=.; \
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
libhydra.la: $(libhydra_la_OBJECTS) $(libhydra_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(libhydra_la_OBJECTS) $(libhydra_la_LIBADD) $(LIBS)
+ $(LINK) -rpath $(ipseclibdir) $(libhydra_la_OBJECTS) $(libhydra_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -437,6 +444,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hydra.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_ipsec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_net.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_pool.Plo@am__quote@
.c.o:
@@ -495,6 +503,13 @@ kernel_ipsec.lo: kernel/kernel_ipsec.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o kernel_ipsec.lo `test -f 'kernel/kernel_ipsec.c' || echo '$(srcdir)/'`kernel/kernel_ipsec.c
+kernel_net.lo: kernel/kernel_net.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT kernel_net.lo -MD -MP -MF $(DEPDIR)/kernel_net.Tpo -c -o kernel_net.lo `test -f 'kernel/kernel_net.c' || echo '$(srcdir)/'`kernel/kernel_net.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/kernel_net.Tpo $(DEPDIR)/kernel_net.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kernel/kernel_net.c' object='kernel_net.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o kernel_net.lo `test -f 'kernel/kernel_net.c' || echo '$(srcdir)/'`kernel/kernel_net.c
+
mostlyclean-libtool:
-rm -f *.lo
@@ -699,7 +714,7 @@ check: check-recursive
all-am: Makefile $(LTLIBRARIES)
installdirs: installdirs-recursive
installdirs-am:
- for dir in "$(DESTDIR)$(libdir)"; do \
+ for dir in "$(DESTDIR)$(ipseclibdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@@ -729,7 +744,7 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive
-clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-recursive
@@ -750,13 +765,13 @@ info: info-recursive
info-am:
-install-data-am:
+install-data-am: install-ipseclibLTLIBRARIES
install-dvi: install-dvi-recursive
install-dvi-am:
-install-exec-am: install-libLTLIBRARIES
+install-exec-am:
install-html: install-html-recursive
@@ -796,26 +811,26 @@ ps: ps-recursive
ps-am:
-uninstall-am: uninstall-libLTLIBRARIES
+uninstall-am: uninstall-ipseclibLTLIBRARIES
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
install-am install-strip tags-recursive
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
all all-am check check-am clean clean-generic \
- clean-libLTLIBRARIES clean-libtool ctags ctags-recursive \
+ clean-ipseclibLTLIBRARIES clean-libtool ctags ctags-recursive \
distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
- install-info-am install-libLTLIBRARIES install-man install-pdf \
- install-pdf-am install-ps install-ps-am install-strip \
- installcheck installcheck-am installdirs installdirs-am \
- maintainer-clean maintainer-clean-generic mostlyclean \
- mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
- pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
- uninstall-libLTLIBRARIES
+ install-info-am install-ipseclibLTLIBRARIES install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-ipseclibLTLIBRARIES
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/libhydra/attributes/attribute_manager.c b/src/libhydra/attributes/attribute_manager.c
index 0d4cbda82..95520531e 100644
--- a/src/libhydra/attributes/attribute_manager.c
+++ b/src/libhydra/attributes/attribute_manager.c
@@ -59,12 +59,9 @@ typedef struct {
host_t *vip;
} enum_data_t;
-/**
- * Implementation of attribute_manager_t.acquire_address.
- */
-static host_t* acquire_address(private_attribute_manager_t *this,
- char *pool, identification_t *id,
- host_t *requested)
+METHOD(attribute_manager_t, acquire_address, host_t*,
+ private_attribute_manager_t *this, char *pool, identification_t *id,
+ host_t *requested)
{
enumerator_t *enumerator;
attribute_provider_t *current;
@@ -90,11 +87,9 @@ static host_t* acquire_address(private_attribute_manager_t *this,
return host;
}
-/**
- * Implementation of attribute_manager_t.release_address.
- */
-static void release_address(private_attribute_manager_t *this,
- char *pool, host_t *address, identification_t *id)
+METHOD(attribute_manager_t, release_address, void,
+ private_attribute_manager_t *this, char *pool, host_t *address,
+ identification_t *id)
{
enumerator_t *enumerator;
attribute_provider_t *current;
@@ -129,12 +124,9 @@ static enumerator_t *responder_enum_create(attribute_provider_t *provider,
data->id, data->vip);
}
-/**
- * Implementation of attribute_manager_t.create_responder_enumerator
- */
-static enumerator_t* create_responder_enumerator(
- private_attribute_manager_t *this, char *pool,
- identification_t *id, host_t *vip)
+METHOD(attribute_manager_t, create_responder_enumerator, enumerator_t*,
+ private_attribute_manager_t *this, char *pool, identification_t *id,
+ host_t *vip)
{
enum_data_t *data = malloc_thing(enum_data_t);
@@ -149,34 +141,26 @@ static enumerator_t* create_responder_enumerator(
(void*)this->lock->unlock, this->lock);
}
-/**
- * Implementation of attribute_manager_t.add_provider.
- */
-static void add_provider(private_attribute_manager_t *this,
- attribute_provider_t *provider)
+METHOD(attribute_manager_t, add_provider, void,
+ private_attribute_manager_t *this, attribute_provider_t *provider)
{
this->lock->write_lock(this->lock);
this->providers->insert_last(this->providers, provider);
this->lock->unlock(this->lock);
}
-/**
- * Implementation of attribute_manager_t.remove_provider.
- */
-static void remove_provider(private_attribute_manager_t *this,
- attribute_provider_t *provider)
+METHOD(attribute_manager_t, remove_provider, void,
+ private_attribute_manager_t *this, attribute_provider_t *provider)
{
this->lock->write_lock(this->lock);
this->providers->remove(this->providers, provider, NULL);
this->lock->unlock(this->lock);
}
-/**
- * Implementation of attribute_manager_t.handle
- */
-static attribute_handler_t* handle(private_attribute_manager_t *this,
- identification_t *server, attribute_handler_t *handler,
- configuration_attribute_type_t type, chunk_t data)
+METHOD(attribute_manager_t, handle, attribute_handler_t*,
+ private_attribute_manager_t *this, identification_t *server,
+ attribute_handler_t *handler, configuration_attribute_type_t type,
+ chunk_t data)
{
enumerator_t *enumerator;
attribute_handler_t *current, *handled = NULL;
@@ -217,13 +201,9 @@ static attribute_handler_t* handle(private_attribute_manager_t *this,
return handled;
}
-/**
- * Implementation of attribute_manager_t.release
- */
-static void release(private_attribute_manager_t *this,
- attribute_handler_t *handler,
- identification_t *server,
- configuration_attribute_type_t type, chunk_t data)
+METHOD(attribute_manager_t, release, void,
+ private_attribute_manager_t *this, attribute_handler_t *handler,
+ identification_t *server, configuration_attribute_type_t type, chunk_t data)
{
enumerator_t *enumerator;
attribute_handler_t *current;
@@ -297,11 +277,8 @@ static void initiator_destroy(initiator_enumerator_t *this)
free(this);
}
-/**
- * Implementation of attribute_manager_t.create_initiator_enumerator
- */
-static enumerator_t* create_initiator_enumerator(
- private_attribute_manager_t *this, identification_t *id, host_t *vip)
+METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*,
+ private_attribute_manager_t *this, identification_t *id, host_t *vip)
{
initiator_enumerator_t *enumerator = malloc_thing(initiator_enumerator_t);
@@ -318,32 +295,24 @@ static enumerator_t* create_initiator_enumerator(
return &enumerator->public;
}
-/**
- * Implementation of attribute_manager_t.add_handler
- */
-static void add_handler(private_attribute_manager_t *this,
- attribute_handler_t *handler)
+METHOD(attribute_manager_t, add_handler, void,
+ private_attribute_manager_t *this, attribute_handler_t *handler)
{
this->lock->write_lock(this->lock);
this->handlers->insert_last(this->handlers, handler);
this->lock->unlock(this->lock);
}
-/**
- * Implementation of attribute_manager_t.remove_handler
- */
-static void remove_handler(private_attribute_manager_t *this,
- attribute_handler_t *handler)
+METHOD(attribute_manager_t, remove_handler, void,
+ private_attribute_manager_t *this, attribute_handler_t *handler)
{
this->lock->write_lock(this->lock);
this->handlers->remove(this->handlers, handler, NULL);
this->lock->unlock(this->lock);
}
-/**
- * Implementation of attribute_manager_t.destroy
- */
-static void destroy(private_attribute_manager_t *this)
+METHOD(attribute_manager_t, destroy, void,
+ private_attribute_manager_t *this)
{
this->providers->destroy(this->providers);
this->handlers->destroy(this->handlers);
@@ -356,23 +325,26 @@ static void destroy(private_attribute_manager_t *this)
*/
attribute_manager_t *attribute_manager_create()
{
- private_attribute_manager_t *this = malloc_thing(private_attribute_manager_t);
-
- this->public.acquire_address = (host_t*(*)(attribute_manager_t*, char*, identification_t*,host_t*))acquire_address;
- this->public.release_address = (void(*)(attribute_manager_t*, char *, host_t*, identification_t*))release_address;
- this->public.create_responder_enumerator = (enumerator_t*(*)(attribute_manager_t*, char *name, identification_t*, host_t*))create_responder_enumerator;
- this->public.add_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))add_provider;
- this->public.remove_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))remove_provider;
- this->public.handle = (attribute_handler_t*(*)(attribute_manager_t*,identification_t*, attribute_handler_t*, configuration_attribute_type_t, chunk_t))handle;
- this->public.release = (void(*)(attribute_manager_t*, attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))release;
- this->public.create_initiator_enumerator = (enumerator_t*(*)(attribute_manager_t*, identification_t*, host_t*))create_initiator_enumerator;
- this->public.add_handler = (void(*)(attribute_manager_t*, attribute_handler_t*))add_handler;
- this->public.remove_handler = (void(*)(attribute_manager_t*, attribute_handler_t*))remove_handler;
- this->public.destroy = (void(*)(attribute_manager_t*))destroy;
-
- this->providers = linked_list_create();
- this->handlers = linked_list_create();
- this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ private_attribute_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .acquire_address = _acquire_address,
+ .release_address = _release_address,
+ .create_responder_enumerator = _create_responder_enumerator,
+ .add_provider = _add_provider,
+ .remove_provider = _remove_provider,
+ .handle = _handle,
+ .release = _release,
+ .create_initiator_enumerator = _create_initiator_enumerator,
+ .add_handler = _add_handler,
+ .remove_handler = _remove_handler,
+ .destroy = _destroy,
+ },
+ .providers = linked_list_create(),
+ .handlers = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
return &this->public;
}
diff --git a/src/libhydra/attributes/attributes.c b/src/libhydra/attributes/attributes.c
index ea87109e2..d8490b7f5 100644
--- a/src/libhydra/attributes/attributes.c
+++ b/src/libhydra/attributes/attributes.c
@@ -17,7 +17,7 @@
#include "attributes.h"
-ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_PREFIX,
+ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, HOME_AGENT_ADDRESS,
"INTERNAL_IP4_ADDRESS",
"INTERNAL_IP4_NETMASK",
"INTERNAL_IP4_DNS",
@@ -35,8 +35,9 @@ ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP
"INTERNAL_IP6_SUBNET",
"MIP6_HOME_PREFIX",
"INTERNAL_IP6_LINK",
- "INTERNAL_IP6_PREFIX");
-ENUM_NEXT(configuration_attribute_type_names, XAUTH_TYPE, XAUTH_ANSWER, INTERNAL_IP6_PREFIX,
+ "INTERNAL_IP6_PREFIX",
+ "HOME_AGENT_ADDRESS");
+ENUM_NEXT(configuration_attribute_type_names, XAUTH_TYPE, XAUTH_ANSWER, HOME_AGENT_ADDRESS,
"XAUTH_TYPE",
"XAUTH_USER_NAME",
"XAUTH_USER_PASSWORD",
@@ -64,7 +65,7 @@ ENUM_NEXT(configuration_attribute_type_names, UNITY_BANNER, UNITY_DDNS_HOSTNAME,
"UNITY_DDNS_HOSTNAME");
ENUM_END(configuration_attribute_type_names, UNITY_DDNS_HOSTNAME);
-ENUM_BEGIN(configuration_attribute_type_short_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_PREFIX,
+ENUM_BEGIN(configuration_attribute_type_short_names, INTERNAL_IP4_ADDRESS, HOME_AGENT_ADDRESS,
"ADDR",
"MASK",
"DNS",
@@ -78,35 +79,36 @@ ENUM_BEGIN(configuration_attribute_type_short_names, INTERNAL_IP4_ADDRESS, INTER
"NBNS6",
"DHCP6",
"SUBNET",
- "SUPPORTED",
+ "SUP",
"SUBNET6",
"MIP6HPFX",
"LINK6",
- "PFX6");
-ENUM_NEXT(configuration_attribute_type_short_names, XAUTH_TYPE, XAUTH_ANSWER, INTERNAL_IP6_PREFIX,
- "XAUTH_TYPE",
- "XAUTH_USER_NAME",
- "XAUTH_USER_PASSWORD",
- "XAUTH_PASSCODE",
- "XAUTH_MESSAGE",
- "XAUTH_CHALLENGE",
- "XAUTH_DOMAIN",
- "XAUTH_STATUS",
- "XAUTH_NEXT_PIN",
- "XAUTH_ANSWER");
+ "PFX6",
+ "HOA");
+ENUM_NEXT(configuration_attribute_type_short_names, XAUTH_TYPE, XAUTH_ANSWER, HOME_AGENT_ADDRESS,
+ "X_TYPE",
+ "X_USER_NAME",
+ "X_USER_PASSWORD",
+ "X_PASSCODE",
+ "X_MESSAGE",
+ "X_CHALLENGE",
+ "X_DOMAIN",
+ "X_STATUS",
+ "X_NEXT_PIN",
+ "X_ANSWER");
ENUM_NEXT(configuration_attribute_type_short_names, INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER, XAUTH_ANSWER,
"SRV",
"SRV6");
ENUM_NEXT(configuration_attribute_type_short_names, UNITY_BANNER, UNITY_DDNS_HOSTNAME, INTERNAL_IP6_SERVER,
- "UNITY_BANNER",
- "UNITY_SAVE_PASSWD",
- "UNITY_DEF_DOMAIN",
- "UNITY_SPLITDNS_NAME",
- "UNITY_SPLIT_INCLUDE",
- "UNITY_NATT_PORT",
- "UNITY_LOCAL_LAN",
- "UNITY_PFS",
- "UNITY_FW_TYPE",
- "UNITY_BACKUP_SERVERS",
- "UNITY_DDNS_HOSTNAME");
+ "U_BANNER",
+ "U_SAVE_PASSWD",
+ "U_DEF_DOMAIN",
+ "U_SPLITDNS_NAME",
+ "U_SPLIT_INCLUDE",
+ "U_NATT_PORT",
+ "U_LOCAL_LAN",
+ "U_PFS",
+ "U_FW_TYPE",
+ "U_BACKUP_SERVERS",
+ "U_DDNS_HOSTNAME");
ENUM_END(configuration_attribute_type_short_names, UNITY_DDNS_HOSTNAME);
diff --git a/src/libhydra/attributes/attributes.h b/src/libhydra/attributes/attributes.h
index 3a40ba367..8ff774b64 100644
--- a/src/libhydra/attributes/attributes.h
+++ b/src/libhydra/attributes/attributes.h
@@ -48,6 +48,7 @@ enum configuration_attribute_type_t {
MIP6_HOME_PREFIX = 16,
INTERNAL_IP6_LINK = 17,
INTERNAL_IP6_PREFIX = 18,
+ HOME_AGENT_ADDRESS = 19,
/* XAUTH attributes */
XAUTH_TYPE = 16520,
XAUTH_USER_NAME = 16521,
diff --git a/src/libhydra/kernel/kernel_interface.c b/src/libhydra/kernel/kernel_interface.c
index 4b5b41f2b..573557506 100644
--- a/src/libhydra/kernel/kernel_interface.c
+++ b/src/libhydra/kernel/kernel_interface.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2010 Tobias Brunner
+ * Copyright (C) 2008-2011 Tobias Brunner
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG
@@ -34,6 +34,16 @@ struct private_kernel_interface_t {
kernel_interface_t public;
/**
+ * Registered IPsec constructor
+ */
+ kernel_ipsec_constructor_t ipsec_constructor;
+
+ /**
+ * Registered net constructor
+ */
+ kernel_net_constructor_t net_constructor;
+
+ /**
* ipsec interface
*/
kernel_ipsec_t *ipsec;
@@ -128,18 +138,28 @@ METHOD(kernel_interface_t, del_sa, status_t,
return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi, mark);
}
+METHOD(kernel_interface_t, flush_sas, status_t,
+ private_kernel_interface_t *this)
+{
+ if (!this->ipsec)
+ {
+ return NOT_SUPPORTED;
+ }
+ return this->ipsec->flush_sas(this->ipsec);
+}
+
METHOD(kernel_interface_t, add_policy, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
- mark_t mark, bool routed)
+ mark_t mark, policy_priority_t priority)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
- direction, type, sa, mark, routed);
+ direction, type, sa, mark, priority);
}
METHOD(kernel_interface_t, query_policy, status_t,
@@ -157,15 +177,25 @@ METHOD(kernel_interface_t, query_policy, status_t,
METHOD(kernel_interface_t, del_policy, status_t,
private_kernel_interface_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
- bool unrouted)
+ traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ mark_t mark, policy_priority_t priority)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts,
- direction, mark, unrouted);
+ direction, reqid, mark, priority);
+}
+
+METHOD(kernel_interface_t, flush_policies, status_t,
+ private_kernel_interface_t *this)
+{
+ if (!this->ipsec)
+ {
+ return NOT_SUPPORTED;
+ }
+ return this->ipsec->flush_policies(this->ipsec);
}
METHOD(kernel_interface_t, get_source_addr, host_t*,
@@ -310,7 +340,7 @@ METHOD(kernel_interface_t, get_address_by_ts, status_t,
if (!found)
{
- DBG1(DBG_KNL, "no local address found in traffic selector %R", ts);
+ DBG2(DBG_KNL, "no local address found in traffic selector %R", ts);
return FAILED;
}
@@ -324,6 +354,7 @@ METHOD(kernel_interface_t, add_ipsec_interface, void,
{
if (!this->ipsec)
{
+ this->ipsec_constructor = constructor;
this->ipsec = constructor();
}
}
@@ -331,7 +362,11 @@ METHOD(kernel_interface_t, add_ipsec_interface, void,
METHOD(kernel_interface_t, remove_ipsec_interface, void,
private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
{
- /* TODO: replace if interface currently in use */
+ if (constructor == this->ipsec_constructor)
+ {
+ this->ipsec->destroy(this->ipsec);
+ this->ipsec = NULL;
+ }
}
METHOD(kernel_interface_t, add_net_interface, void,
@@ -339,6 +374,7 @@ METHOD(kernel_interface_t, add_net_interface, void,
{
if (!this->net)
{
+ this->net_constructor = constructor;
this->net = constructor();
}
}
@@ -346,7 +382,11 @@ METHOD(kernel_interface_t, add_net_interface, void,
METHOD(kernel_interface_t, remove_net_interface, void,
private_kernel_interface_t *this, kernel_net_constructor_t constructor)
{
- /* TODO: replace if interface currently in use */
+ if (constructor == this->net_constructor)
+ {
+ this->net->destroy(this->net);
+ this->net = NULL;
+ }
}
METHOD(kernel_interface_t, add_listener, void,
@@ -485,9 +525,11 @@ kernel_interface_t *kernel_interface_create()
.update_sa = _update_sa,
.query_sa = _query_sa,
.del_sa = _del_sa,
+ .flush_sas = _flush_sas,
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
+ .flush_policies = _flush_policies,
.get_source_addr = _get_source_addr,
.get_nexthop = _get_nexthop,
.get_interface = _get_interface,
diff --git a/src/libhydra/kernel/kernel_interface.h b/src/libhydra/kernel/kernel_interface.h
index 471a1d5d3..991cfafd0 100644
--- a/src/libhydra/kernel/kernel_interface.h
+++ b/src/libhydra/kernel/kernel_interface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2010 Tobias Brunner
+ * Copyright (C) 2006-2011 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -175,6 +175,13 @@ struct kernel_interface_t {
mark_t mark);
/**
+ * Flush all SAs from the SAD.
+ *
+ * @return SUCCESS if operation completed
+ */
+ status_t (*flush_sas) (kernel_interface_t *this);
+
+ /**
* Add a policy to the SPD.
*
* A policy is always associated to an SA. Traffic which matches a
@@ -188,7 +195,7 @@ struct kernel_interface_t {
* @param type type of policy, POLICY_(IPSEC|PASS|DROP)
* @param sa details about the SA(s) tied to this policy
* @param mark mark for this policy
- * @param routed TRUE, if this policy is routed in the kernel
+ * @param priority priority of this policy
* @return SUCCESS if operation completed
*/
status_t (*add_policy) (kernel_interface_t *this,
@@ -196,7 +203,8 @@ struct kernel_interface_t {
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type,
- ipsec_sa_cfg_t *sa, mark_t mark, bool routed);
+ ipsec_sa_cfg_t *sa, mark_t mark,
+ policy_priority_t priority);
/**
* Query the use time of a policy.
@@ -228,15 +236,23 @@ struct kernel_interface_t {
* @param src_ts traffic selector to match traffic source
* @param dst_ts traffic selector to match traffic dest
* @param direction direction of traffic, POLICY_(IN|OUT|FWD)
+ * @param reqid unique ID of the associated SA
* @param mark optional mark
- * @param unrouted TRUE, if this policy is unrouted from the kernel
+ * @param priority priority of the policy
* @return SUCCESS if operation completed
*/
status_t (*del_policy) (kernel_interface_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
- policy_dir_t direction, mark_t mark,
- bool unrouted);
+ policy_dir_t direction, u_int32_t reqid,
+ mark_t mark, policy_priority_t priority);
+
+ /**
+ * Flush all policies from the SPD.
+ *
+ * @return SUCCESS if operation completed
+ */
+ status_t (*flush_policies) (kernel_interface_t *this);
/**
* Get our outgoing source address for a destination.
diff --git a/src/libhydra/kernel/kernel_ipsec.c b/src/libhydra/kernel/kernel_ipsec.c
index 383685426..9b38297cc 100644
--- a/src/libhydra/kernel/kernel_ipsec.c
+++ b/src/libhydra/kernel/kernel_ipsec.c
@@ -15,10 +15,14 @@
#include "kernel_ipsec.h"
-ENUM(ipsec_mode_names, MODE_TRANSPORT, MODE_BEET,
+#include <hydra.h>
+
+ENUM(ipsec_mode_names, MODE_TRANSPORT, MODE_DROP,
"TRANSPORT",
"TUNNEL",
"BEET",
+ "PASS",
+ "DROP"
);
ENUM(policy_dir_names, POLICY_IN, POLICY_FWD,
@@ -35,3 +39,21 @@ ENUM(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_LZJH,
"IPCOMP_LZJH"
);
+/**
+ * See header
+ */
+bool kernel_ipsec_register(plugin_t *plugin, plugin_feature_t *feature,
+ bool reg, void *data)
+{
+ if (reg)
+ {
+ hydra->kernel_interface->add_ipsec_interface(hydra->kernel_interface,
+ (kernel_ipsec_constructor_t)data);
+ }
+ else
+ {
+ hydra->kernel_interface->remove_ipsec_interface(hydra->kernel_interface,
+ (kernel_ipsec_constructor_t)data);
+ }
+ return TRUE;
+}
diff --git a/src/libhydra/kernel/kernel_ipsec.h b/src/libhydra/kernel/kernel_ipsec.h
index ef36efd11..ddb63283c 100644
--- a/src/libhydra/kernel/kernel_ipsec.h
+++ b/src/libhydra/kernel/kernel_ipsec.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2010 Tobias Brunner
+ * Copyright (C) 2006-2011 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -27,6 +27,7 @@
typedef enum ipsec_mode_t ipsec_mode_t;
typedef enum policy_dir_t policy_dir_t;
typedef enum policy_type_t policy_type_t;
+typedef enum policy_priority_t policy_priority_t;
typedef enum ipcomp_transform_t ipcomp_transform_t;
typedef struct kernel_ipsec_t kernel_ipsec_t;
typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t;
@@ -36,6 +37,7 @@ typedef struct mark_t mark_t;
#include <utils/host.h>
#include <crypto/prf_plus.h>
#include <selectors/traffic_selector.h>
+#include <plugins/plugin.h>
/**
* Mode of an IPsec SA.
@@ -47,6 +49,10 @@ enum ipsec_mode_t {
MODE_TUNNEL,
/** BEET mode, tunnel mode but fixed, bound inner addresses */
MODE_BEET,
+ /** passthrough policy for traffic without an IPsec SA */
+ MODE_PASS,
+ /** drop policy discarding traffic */
+ MODE_DROP
};
/**
@@ -86,6 +92,18 @@ enum policy_type_t {
};
/**
+ * High-level priority of a policy.
+ */
+enum policy_priority_t {
+ /** Default priority */
+ POLICY_PRIORITY_DEFAULT,
+ /** Priority for trap policies */
+ POLICY_PRIORITY_ROUTED,
+ /** Priority for fallback drop policies */
+ POLICY_PRIORITY_FALLBACK,
+};
+
+/**
* IPComp transform IDs, as in RFC 4306
*/
enum ipcomp_transform_t {
@@ -288,6 +306,13 @@ struct kernel_ipsec_t {
mark_t mark);
/**
+ * Flush all SAs from the SAD.
+ *
+ * @return SUCCESS if operation completed
+ */
+ status_t (*flush_sas) (kernel_ipsec_t *this);
+
+ /**
* Add a policy to the SPD.
*
* A policy is always associated to an SA. Traffic which matches a
@@ -301,7 +326,7 @@ struct kernel_ipsec_t {
* @param type type of policy, POLICY_(IPSEC|PASS|DROP)
* @param sa details about the SA(s) tied to this policy
* @param mark mark for this policy
- * @param routed TRUE, if this policy is routed in the kernel
+ * @param priority priority of this policy
* @return SUCCESS if operation completed
*/
status_t (*add_policy) (kernel_ipsec_t *this,
@@ -309,7 +334,8 @@ struct kernel_ipsec_t {
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type,
- ipsec_sa_cfg_t *sa, mark_t mark, bool routed);
+ ipsec_sa_cfg_t *sa, mark_t mark,
+ policy_priority_t priority);
/**
* Query the use time of a policy.
@@ -342,15 +368,23 @@ struct kernel_ipsec_t {
* @param src_ts traffic selector to match traffic source
* @param dst_ts traffic selector to match traffic dest
* @param direction direction of traffic, POLICY_(IN|OUT|FWD)
+ * @param reqid unique ID of the associated SA
* @param mark optional mark
- * @param unrouted TRUE, if this policy is unrouted from the kernel
+ * @param priority priority of the policy
* @return SUCCESS if operation completed
*/
status_t (*del_policy) (kernel_ipsec_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
- policy_dir_t direction, mark_t mark,
- bool unrouted);
+ policy_dir_t direction, u_int32_t reqid,
+ mark_t mark, policy_priority_t priority);
+
+ /**
+ * Flush all policies from the SPD.
+ *
+ * @return SUCCESS if operation completed
+ */
+ status_t (*flush_policies) (kernel_ipsec_t *this);
/**
* Install a bypass policy for the given socket.
@@ -367,4 +401,18 @@ struct kernel_ipsec_t {
void (*destroy) (kernel_ipsec_t *this);
};
+/**
+ * Helper function to (un-)register IPsec kernel interfaces from plugin features.
+ *
+ * This function is a plugin_feature_callback_t and can be used with the
+ * PLUGIN_CALLBACK macro to register an IPsec kernel interface constructor.
+ *
+ * @param plugin plugin registering the kernel interface
+ * @param feature associated plugin feature
+ * @param reg TRUE to register, FALSE to unregister
+ * @param data data passed to callback, an kernel_ipsec_constructor_t
+ */
+bool kernel_ipsec_register(plugin_t *plugin, plugin_feature_t *feature,
+ bool reg, void *data);
+
#endif /** KERNEL_IPSEC_H_ @}*/
diff --git a/src/libhydra/kernel/kernel_listener.h b/src/libhydra/kernel/kernel_listener.h
index 6f2dbd23b..5db297b6f 100644
--- a/src/libhydra/kernel/kernel_listener.h
+++ b/src/libhydra/kernel/kernel_listener.h
@@ -84,7 +84,7 @@ struct kernel_listener_t {
policy_dir_t direction, host_t *local, host_t *remote);
/**
- * Hook called if changes in the networking layer occured (interfaces
+ * Hook called if changes in the networking layer occurred (interfaces
* up/down, routes added/deleted etc.).
*
* @param address TRUE if address list, FALSE if routing changed
diff --git a/src/libhydra/kernel/kernel_net.c b/src/libhydra/kernel/kernel_net.c
new file mode 100644
index 000000000..0841ed803
--- /dev/null
+++ b/src/libhydra/kernel/kernel_net.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "kernel_net.h"
+
+#include <hydra.h>
+
+/**
+ * See header
+ */
+bool kernel_net_register(plugin_t *plugin, plugin_feature_t *feature,
+ bool reg, void *data)
+{
+ if (reg)
+ {
+ hydra->kernel_interface->add_net_interface(hydra->kernel_interface,
+ (kernel_net_constructor_t)data);
+ }
+ else
+ {
+ hydra->kernel_interface->remove_net_interface(hydra->kernel_interface,
+ (kernel_net_constructor_t)data);
+ }
+ return TRUE;
+}
diff --git a/src/libhydra/kernel/kernel_net.h b/src/libhydra/kernel/kernel_net.h
index 69e01f43f..a89e76804 100644
--- a/src/libhydra/kernel/kernel_net.h
+++ b/src/libhydra/kernel/kernel_net.h
@@ -26,6 +26,7 @@ typedef struct kernel_net_t kernel_net_t;
#include <utils/enumerator.h>
#include <utils/host.h>
+#include <plugins/plugin.h>
/**
* Interface to the network subsystem of the kernel.
@@ -142,4 +143,18 @@ struct kernel_net_t {
void (*destroy) (kernel_net_t *this);
};
+/**
+ * Helper function to (un-)register net kernel interfaces from plugin features.
+ *
+ * This function is a plugin_feature_callback_t and can be used with the
+ * PLUGIN_CALLBACK macro to register an net kernel interface constructor.
+ *
+ * @param plugin plugin registering the kernel interface
+ * @param feature associated plugin feature
+ * @param reg TRUE to register, FALSE to unregister
+ * @param data data passed to callback, an kernel_net_constructor_t
+ */
+bool kernel_net_register(plugin_t *plugin, plugin_feature_t *feature,
+ bool reg, void *data);
+
#endif /** KERNEL_NET_H_ @}*/
diff --git a/src/libhydra/plugins/attr/Makefile.in b/src/libhydra/plugins/attr/Makefile.in
index 250ac9539..1ceb93ef3 100644
--- a/src/libhydra/plugins/attr/Makefile.in
+++ b/src/libhydra/plugins/attr/Makefile.in
@@ -191,6 +191,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -199,6 +202,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -215,11 +219,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -263,6 +269,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
diff --git a/src/libhydra/plugins/attr_sql/Makefile.in b/src/libhydra/plugins/attr_sql/Makefile.in
index 80d497f59..4fe577f3b 100644
--- a/src/libhydra/plugins/attr_sql/Makefile.in
+++ b/src/libhydra/plugins/attr_sql/Makefile.in
@@ -204,6 +204,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -212,6 +215,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -228,11 +232,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -276,6 +282,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
diff --git a/src/libhydra/plugins/attr_sql/pool.c b/src/libhydra/plugins/attr_sql/pool.c
index e81a23ed9..a2000cffe 100644
--- a/src/libhydra/plugins/attr_sql/pool.c
+++ b/src/libhydra/plugins/attr_sql/pool.c
@@ -305,6 +305,11 @@ static void status(void)
lease->enumerate(lease, &size);
lease->destroy(lease);
}
+ if (!size)
+ { /* empty pool */
+ printf("%6d %11s %11s ", 0, "n/a", "n/a");
+ goto next_pool;
+ }
printf("%6d ", size);
/* get number of online hosts */
lease = db->query(db, "SELECT COUNT(*) FROM addresses "
@@ -316,7 +321,7 @@ static void status(void)
lease->destroy(lease);
}
printf("%5d (%2d%%) ", online, online*100/size);
- /* get number of online or valid lieases */
+ /* get number of online or valid leases */
lease = db->query(db, "SELECT COUNT(*) FROM addresses "
"WHERE addresses.pool = ? "
"AND ((? AND acquired != 0) "
@@ -330,6 +335,7 @@ static void status(void)
}
printf("%5d (%2d%%) ", used, used*100/size);
+next_pool:
printf("\n");
DESTROY_IF(start);
DESTROY_IF(end);
diff --git a/src/libhydra/plugins/attr_sql/sql_attribute.c b/src/libhydra/plugins/attr_sql/sql_attribute.c
index 7f7bb190c..714bbcd72 100644
--- a/src/libhydra/plugins/attr_sql/sql_attribute.c
+++ b/src/libhydra/plugins/attr_sql/sql_attribute.c
@@ -38,7 +38,7 @@ struct private_sql_attribute_t {
database_t *db;
/**
- * wheter to record lease history in lease table
+ * whether to record lease history in lease table
*/
bool history;
};
@@ -232,12 +232,9 @@ static host_t* get_lease(private_sql_attribute_t *this, char *name,
return NULL;
}
-/**
- * Implementation of attribute_provider_t.acquire_address
- */
-static host_t* acquire_address(private_sql_attribute_t *this,
- char *names, identification_t *id,
- host_t *requested)
+METHOD(attribute_provider_t, acquire_address, host_t*,
+ private_sql_attribute_t *this, char *names, identification_t *id,
+ host_t *requested)
{
host_t *address = NULL;
u_int identity, pool, timeout;
@@ -302,11 +299,9 @@ static host_t* acquire_address(private_sql_attribute_t *this,
return address;
}
-/**
- * Implementation of attribute_provider_t.release_address
- */
-static bool release_address(private_sql_attribute_t *this,
- char *name, host_t *address, identification_t *id)
+METHOD(attribute_provider_t, release_address, bool,
+ private_sql_attribute_t *this, char *name, host_t *address,
+ identification_t *id)
{
enumerator_t *enumerator;
bool found = FALSE;
@@ -343,11 +338,9 @@ static bool release_address(private_sql_attribute_t *this,
return found;
}
-/**
- * Implementation of sql_attribute_t.create_attribute_enumerator
- */
-static enumerator_t* create_attribute_enumerator(private_sql_attribute_t *this,
- char *names, identification_t *id, host_t *vip)
+METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
+ private_sql_attribute_t *this, char *names, identification_t *id,
+ host_t *vip)
{
enumerator_t *attr_enumerator = NULL;
@@ -444,10 +437,8 @@ static enumerator_t* create_attribute_enumerator(private_sql_attribute_t *this,
return (attr_enumerator ? attr_enumerator : enumerator_create_empty());
}
-/**
- * Implementation of sql_attribute_t.destroy
- */
-static void destroy(private_sql_attribute_t *this)
+METHOD(sql_attribute_t, destroy, void,
+ private_sql_attribute_t *this)
{
free(this);
}
@@ -457,17 +448,22 @@ static void destroy(private_sql_attribute_t *this)
*/
sql_attribute_t *sql_attribute_create(database_t *db)
{
- private_sql_attribute_t *this = malloc_thing(private_sql_attribute_t);
+ private_sql_attribute_t *this;
time_t now = time(NULL);
- this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *, host_t *))acquire_address;
- this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *, identification_t*))release_address;
- this->public.provider.create_attribute_enumerator = (enumerator_t*(*)(attribute_provider_t*, char *names, identification_t *id, host_t *host))create_attribute_enumerator;
- this->public.destroy = (void(*)(sql_attribute_t*))destroy;
-
- this->db = db;
- this->history = lib->settings->get_bool(lib->settings,
- "libhydra.plugins.attr-sql.lease_history", TRUE);
+ INIT(this,
+ .public = {
+ .provider = {
+ .acquire_address = _acquire_address,
+ .release_address = _release_address,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ },
+ .destroy = _destroy,
+ },
+ .db = db,
+ .history = lib->settings->get_bool(lib->settings,
+ "libhydra.plugins.attr-sql.lease_history", TRUE),
+ );
/* close any "online" leases in the case we crashed */
if (this->history)
diff --git a/src/libhydra/plugins/kernel_klips/Makefile.in b/src/libhydra/plugins/kernel_klips/Makefile.in
index 5f6512b44..63f3e045b 100644
--- a/src/libhydra/plugins/kernel_klips/Makefile.in
+++ b/src/libhydra/plugins/kernel_klips/Makefile.in
@@ -195,6 +195,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -203,6 +206,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -219,11 +223,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -267,6 +273,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
diff --git a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c
index ff4f0ed55..ceff8cdc9 100644
--- a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c
+++ b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c
@@ -1971,7 +1971,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
- mark_t mark, bool routed)
+ mark_t mark, policy_priority_t priority)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -2013,7 +2013,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
this->policies->insert_last(this->policies, policy);
}
- if (routed)
+ if (priority == POLICY_PRIORITY_ROUTED)
{
/* we install this as a %trap eroute in the kernel, later to be
* triggered by packets matching the policy (-> ACQUIRE). */
@@ -2049,9 +2049,11 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
msg = (struct sadb_msg*)request;
/* FIXME: SADB_X_SAFLAGS_INFLOW may be required, if we add an inbound policy for an IPIP SA */
- build_addflow(msg, satype, spi, routed ? NULL : src, routed ? NULL : dst,
- policy->src.net, policy->src.mask, policy->dst.net, policy->dst.mask,
- policy->src.proto, found != NULL);
+ build_addflow(msg, satype, spi,
+ priority == POLICY_PRIORITY_ROUTED ? NULL : src,
+ priority == POLICY_PRIORITY_ROUTED ? NULL : dst,
+ policy->src.net, policy->src.mask, policy->dst.net,
+ policy->dst.mask, policy->src.proto, found != NULL);
this->mutex->unlock(this->mutex);
@@ -2347,8 +2349,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
- bool unrouted)
+ traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ mark_t mark, policy_priority_t priority)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg = (struct sadb_msg*)request, *out;
@@ -2382,7 +2384,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
policy_entry_destroy(policy);
/* decrease appropriate counter */
- unrouted ? found->trapcount-- : found->activecount--;
+ priority == POLICY_PRIORITY_ROUTED ? found->trapcount--
+ : found->activecount--;
if (found->trapcount == 0)
{
@@ -2507,7 +2510,7 @@ static void init_ipsec_devices(private_kernel_klips_ipsec_t *this)
}
/**
- * Register a socket for AQUIRE/EXPIRE messages
+ * Register a socket for ACQUIRE/EXPIRE messages
*/
static status_t register_pfkey_socket(private_kernel_klips_ipsec_t *this, u_int8_t satype)
{
@@ -2586,9 +2589,11 @@ kernel_klips_ipsec_t *kernel_klips_ipsec_create()
.update_sa = _update_sa,
.query_sa = _query_sa,
.del_sa = _del_sa,
+ .flush_sas = (void*)return_failed,
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
+ .flush_policies = (void*)return_failed,
.bypass_socket = _bypass_socket,
.destroy = _destroy,
},
@@ -2634,8 +2639,8 @@ kernel_klips_ipsec_t *kernel_klips_ipsec_create()
return NULL;
}
- this->job = callback_job_create((callback_job_cb_t)receive_events,
- this, NULL, NULL);
+ this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
lib->processor->queue_job(lib->processor, (job_t*)this->job);
return &this->public;
diff --git a/src/libhydra/plugins/kernel_klips/kernel_klips_plugin.c b/src/libhydra/plugins/kernel_klips/kernel_klips_plugin.c
index 7fe47f630..ab02ba711 100644
--- a/src/libhydra/plugins/kernel_klips/kernel_klips_plugin.c
+++ b/src/libhydra/plugins/kernel_klips/kernel_klips_plugin.c
@@ -38,11 +38,20 @@ METHOD(plugin_t, get_name, char*,
return "kernel-klips";
}
+METHOD(plugin_t, get_features, int,
+ private_kernel_klips_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(kernel_ipsec_register, kernel_klips_ipsec_create),
+ PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
+ };
+ *features = f;
+ return countof(f);
+}
+
METHOD(plugin_t, destroy, void,
private_kernel_klips_plugin_t *this)
{
- hydra->kernel_interface->remove_ipsec_interface(hydra->kernel_interface,
- (kernel_ipsec_constructor_t)kernel_klips_ipsec_create);
free(this);
}
@@ -57,13 +66,11 @@ plugin_t *kernel_klips_plugin_create()
.public = {
.plugin = {
.get_name = _get_name,
- .reload = (void*)return_false,
+ .get_features = _get_features,
.destroy = _destroy,
},
},
);
- hydra->kernel_interface->add_ipsec_interface(hydra->kernel_interface,
- (kernel_ipsec_constructor_t)kernel_klips_ipsec_create);
return &this->public.plugin;
}
diff --git a/src/libhydra/plugins/kernel_netlink/Makefile.in b/src/libhydra/plugins/kernel_netlink/Makefile.in
index 78dfb1b54..73dbdd0e3 100644
--- a/src/libhydra/plugins/kernel_netlink/Makefile.in
+++ b/src/libhydra/plugins/kernel_netlink/Makefile.in
@@ -196,6 +196,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -204,6 +207,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -220,11 +224,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -268,6 +274,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
index 8b2a1aa77..b2cf778be 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2010 Tobias Brunner
+ * Copyright (C) 2006-2011 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2008 Andreas Steffen
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
@@ -40,32 +40,32 @@
#include <threading/thread.h>
#include <threading/mutex.h>
#include <utils/hashtable.h>
+#include <utils/linked_list.h>
#include <processing/jobs/callback_job.h>
-/** required for Linux 2.6.26 kernel and later */
+/** Required for Linux 2.6.26 kernel and later */
#ifndef XFRM_STATE_AF_UNSPEC
-#define XFRM_STATE_AF_UNSPEC 32
+#define XFRM_STATE_AF_UNSPEC 32
#endif
-/** from linux/in.h */
+/** From linux/in.h */
#ifndef IP_XFRM_POLICY
#define IP_XFRM_POLICY 17
#endif
-/* missing on uclibc */
+/** Missing on uclibc */
#ifndef IPV6_XFRM_POLICY
#define IPV6_XFRM_POLICY 34
#endif /*IPV6_XFRM_POLICY*/
-/** default priority of installed policies */
-#define PRIO_LOW 1024
-#define PRIO_HIGH 512
+/** Default priority of installed policies */
+#define PRIO_BASE 512
-/** default replay window size, if not set using charon.replay_window */
+/** Default replay window size, if not set using charon.replay_window */
#define DEFAULT_REPLAY_WINDOW 32
/**
- * map the limit for bytes and packets to XFRM_INF per default
+ * Map the limit for bytes and packets to XFRM_INF by default
*/
#define XFRM_LIMIT(x) ((x) == 0 ? XFRM_INF : (x))
@@ -75,17 +75,19 @@
#define XFRMNLGRP(x) (1<<(XFRMNLGRP_##x-1))
/**
- * returns a pointer to the first rtattr following the nlmsghdr *nlh and the
+ * Returns a pointer to the first rtattr following the nlmsghdr *nlh and the
* 'usual' netlink data x like 'struct xfrm_usersa_info'
*/
-#define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(x))))
+#define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + \
+ NLMSG_ALIGN(sizeof(x))))
/**
- * returns a pointer to the next rtattr following rta.
- * !!! do not use this to parse messages. use RTA_NEXT and RTA_OK instead !!!
+ * Returns a pointer to the next rtattr following rta.
+ * !!! Do not use this to parse messages. Use RTA_NEXT and RTA_OK instead !!!
*/
-#define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + \
+ RTA_ALIGN((rta)->rta_len)))
/**
- * returns the total size of attached rta data
+ * Returns the total size of attached rta data
* (after 'usual' netlink data x like 'struct xfrm_usersa_info')
*/
#define XFRM_PAYLOAD(nlh, x) NLMSG_PAYLOAD(nlh, sizeof(x))
@@ -133,7 +135,7 @@ ENUM(xfrm_msg_names, XFRM_MSG_NEWSA, XFRM_MSG_MAPPING,
"XFRM_MSG_MAPPING"
);
-ENUM(xfrm_attr_type_names, XFRMA_UNSPEC, XFRMA_KMADDRESS,
+ENUM(xfrm_attr_type_names, XFRMA_UNSPEC, XFRMA_REPLAY_ESN_VAL,
"XFRMA_UNSPEC",
"XFRMA_ALG_AUTH",
"XFRMA_ALG_CRYPT",
@@ -153,7 +155,11 @@ ENUM(xfrm_attr_type_names, XFRMA_UNSPEC, XFRMA_KMADDRESS,
"XFRMA_POLICY_TYPE",
"XFRMA_MIGRATE",
"XFRMA_ALG_AEAD",
- "XFRMA_KMADDRESS"
+ "XFRMA_KMADDRESS",
+ "XFRMA_ALG_AUTH_TRUNC",
+ "XFRMA_MARK",
+ "XFRMA_TFCPAD",
+ "XFRMA_REPLAY_ESN_VAL",
);
#define END_OF_LIST -1
@@ -196,7 +202,9 @@ static kernel_algorithm_t encryption_algs[] = {
*/
static kernel_algorithm_t integrity_algs[] = {
{AUTH_HMAC_MD5_96, "md5" },
+ {AUTH_HMAC_MD5_128, "hmac(md5)" },
{AUTH_HMAC_SHA1_96, "sha1" },
+ {AUTH_HMAC_SHA1_160, "hmac(sha1)" },
{AUTH_HMAC_SHA2_256_96, "sha256" },
{AUTH_HMAC_SHA2_256_128, "hmac(sha256)" },
{AUTH_HMAC_SHA2_384_192, "hmac(sha384)" },
@@ -234,10 +242,72 @@ static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2)
return NULL;
}
+typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t;
+
+/**
+ * Private variables and functions of kernel_netlink class.
+ */
+struct private_kernel_netlink_ipsec_t {
+ /**
+ * Public part of the kernel_netlink_t object
+ */
+ kernel_netlink_ipsec_t public;
+
+ /**
+ * Mutex to lock access to installed policies
+ */
+ mutex_t *mutex;
+
+ /**
+ * Hash table of installed policies (policy_entry_t)
+ */
+ hashtable_t *policies;
+
+ /**
+ * Hash table of IPsec SAs using policies (ipsec_sa_t)
+ */
+ hashtable_t *sas;
+
+ /**
+ * Job receiving netlink events
+ */
+ callback_job_t *job;
+
+ /**
+ * Netlink xfrm socket (IPsec)
+ */
+ netlink_socket_t *socket_xfrm;
+
+ /**
+ * Netlink xfrm socket to receive acquire and expire events
+ */
+ int socket_xfrm_events;
+
+ /**
+ * Whether to install routes along policies
+ */
+ bool install_routes;
+
+ /**
+ * Whether to track the history of a policy
+ */
+ bool policy_history;
+
+ /**
+ * Size of the replay window, in packets
+ */
+ u_int32_t replay_window;
+
+ /**
+ * Size of the replay window bitmap, in bytes
+ */
+ u_int32_t replay_bmp;
+};
+
typedef struct route_entry_t route_entry_t;
/**
- * installed routing entry
+ * Installed routing entry
*/
struct route_entry_t {
/** Name of the interface the route is bound to */
@@ -246,7 +316,7 @@ struct route_entry_t {
/** Source ip of the route */
host_t *src_ip;
- /** gateway for this route */
+ /** Gateway for this route */
host_t *gateway;
/** Destination net */
@@ -257,7 +327,7 @@ struct route_entry_t {
};
/**
- * destroy an route_entry_t object
+ * Destroy a route_entry_t object
*/
static void route_entry_destroy(route_entry_t *this)
{
@@ -268,30 +338,226 @@ static void route_entry_destroy(route_entry_t *this)
free(this);
}
+/**
+ * Compare two route_entry_t objects
+ */
+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->equals(a->src_ip, b->src_ip) &&
+ a->gateway->equals(a->gateway, b->gateway) &&
+ chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen;
+}
+
+typedef struct ipsec_sa_t ipsec_sa_t;
+
+/**
+ * IPsec SA assigned to a policy.
+ */
+struct ipsec_sa_t {
+ /** Source address of this SA */
+ host_t *src;
+
+ /** Destination address of this SA */
+ host_t *dst;
+
+ /** Optional mark */
+ mark_t mark;
+
+ /** Description of this SA */
+ ipsec_sa_cfg_t cfg;
+
+ /** Reference count for this SA */
+ refcount_t refcount;
+};
+
+/**
+ * Hash function for ipsec_sa_t objects
+ */
+static u_int ipsec_sa_hash(ipsec_sa_t *sa)
+{
+ return chunk_hash_inc(sa->src->get_address(sa->src),
+ chunk_hash_inc(sa->dst->get_address(sa->dst),
+ chunk_hash_inc(chunk_from_thing(sa->mark),
+ chunk_hash(chunk_from_thing(sa->cfg)))));
+}
+
+/**
+ * Equality function for ipsec_sa_t objects
+ */
+static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa)
+{
+ return sa->src->ip_equals(sa->src, other_sa->src) &&
+ sa->dst->ip_equals(sa->dst, other_sa->dst) &&
+ memeq(&sa->mark, &other_sa->mark, sizeof(mark_t)) &&
+ memeq(&sa->cfg, &other_sa->cfg, sizeof(ipsec_sa_cfg_t));
+}
+
+/**
+ * Allocate or reference an IPsec SA object
+ */
+static ipsec_sa_t *ipsec_sa_create(private_kernel_netlink_ipsec_t *this,
+ host_t *src, host_t *dst, mark_t mark,
+ ipsec_sa_cfg_t *cfg)
+{
+ ipsec_sa_t *sa, *found;
+ INIT(sa,
+ .src = src,
+ .dst = dst,
+ .mark = mark,
+ .cfg = *cfg,
+ );
+ found = this->sas->get(this->sas, sa);
+ if (!found)
+ {
+ sa->src = src->clone(src);
+ sa->dst = dst->clone(dst);
+ this->sas->put(this->sas, sa, sa);
+ }
+ else
+ {
+ free(sa);
+ sa = found;
+ }
+ ref_get(&sa->refcount);
+ return sa;
+}
+
+/**
+ * Release and destroy an IPsec SA object
+ */
+static void ipsec_sa_destroy(private_kernel_netlink_ipsec_t *this,
+ ipsec_sa_t *sa)
+{
+ if (ref_put(&sa->refcount))
+ {
+ this->sas->remove(this->sas, sa);
+ DESTROY_IF(sa->src);
+ DESTROY_IF(sa->dst);
+ free(sa);
+ }
+}
+
+typedef struct policy_sa_t policy_sa_t;
+typedef struct policy_sa_fwd_t policy_sa_fwd_t;
+
+/**
+ * Mapping between a policy and an IPsec SA.
+ */
+struct policy_sa_t {
+ /** Priority assigned to the policy when installed with this SA */
+ u_int32_t priority;
+
+ /** Type of the policy */
+ policy_type_t type;
+
+ /** Assigned SA */
+ ipsec_sa_t *sa;
+};
+
+/**
+ * For forward policies we also cache the traffic selectors in order to install
+ * the route.
+ */
+struct policy_sa_fwd_t {
+ /** Generic interface */
+ policy_sa_t generic;
+
+ /** Source traffic selector of this policy */
+ traffic_selector_t *src_ts;
+
+ /** Destination traffic selector of this policy */
+ traffic_selector_t *dst_ts;
+};
+
+/**
+ * Create a policy_sa(_fwd)_t object
+ */
+static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
+ policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts, mark_t mark,
+ ipsec_sa_cfg_t *cfg)
+{
+ policy_sa_t *policy;
+
+ if (dir == POLICY_FWD)
+ {
+ policy_sa_fwd_t *fwd;
+ INIT(fwd,
+ .src_ts = src_ts->clone(src_ts),
+ .dst_ts = dst_ts->clone(dst_ts),
+ );
+ policy = &fwd->generic;
+ }
+ else
+ {
+ INIT(policy, .priority = 0);
+ }
+ policy->type = type;
+ policy->sa = ipsec_sa_create(this, src, dst, mark, cfg);
+ return policy;
+}
+
+/**
+ * Destroy a policy_sa(_fwd)_t object
+ */
+static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
+ private_kernel_netlink_ipsec_t *this)
+{
+ if (*dir == POLICY_FWD)
+ {
+ policy_sa_fwd_t *fwd = (policy_sa_fwd_t*)policy;
+ fwd->src_ts->destroy(fwd->src_ts);
+ fwd->dst_ts->destroy(fwd->dst_ts);
+ }
+ ipsec_sa_destroy(this, policy->sa);
+ free(policy);
+}
+
typedef struct policy_entry_t policy_entry_t;
/**
- * installed kernel policy.
+ * Installed kernel policy.
*/
struct policy_entry_t {
- /** direction of this policy: in, out, forward */
+ /** Direction of this policy: in, out, forward */
u_int8_t direction;
- /** parameters of installed policy */
+ /** Parameters of installed policy */
struct xfrm_selector sel;
- /** optional mark */
+ /** Optional mark */
u_int32_t mark;
- /** associated route installed for this policy */
+ /** Associated route installed for this policy */
route_entry_t *route;
- /** by how many CHILD_SA's this policy is used */
- u_int refcount;
+ /** List of SAs this policy is used by, ordered by priority */
+ linked_list_t *used_by;
};
/**
+ * Destroy a policy_entry_t object
+ */
+static void policy_entry_destroy(private_kernel_netlink_ipsec_t *this,
+ policy_entry_t *policy)
+{
+ if (policy->route)
+ {
+ route_entry_destroy(policy->route);
+ }
+ 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->destroy(policy->used_by);
+ }
+ free(policy);
+}
+
+/**
* Hash function for policy_entry_t objects
*/
static u_int policy_hash(policy_entry_t *key)
@@ -311,60 +577,35 @@ static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)
key->direction == other_key->direction;
}
-typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t;
-
/**
- * Private variables and functions of kernel_netlink class.
+ * Calculate the priority of a policy
*/
-struct private_kernel_netlink_ipsec_t {
- /**
- * Public part of the kernel_netlink_t object.
- */
- kernel_netlink_ipsec_t public;
-
- /**
- * mutex to lock access to various lists
- */
- mutex_t *mutex;
-
- /**
- * Hash table of installed policies (policy_entry_t)
- */
- hashtable_t *policies;
-
- /**
- * job receiving netlink events
- */
- callback_job_t *job;
-
- /**
- * Netlink xfrm socket (IPsec)
- */
- netlink_socket_t *socket_xfrm;
-
- /**
- * netlink xfrm socket to receive acquire and expire events
- */
- int socket_xfrm_events;
-
- /**
- * whether to install routes along policies
- */
- bool install_routes;
-
- /**
- * Size of the replay window, in packets
- */
- u_int32_t replay_window;
-
- /**
- * Size of the replay window bitmap, in bytes
- */
- u_int32_t replay_bmp;
-};
+static inline u_int32_t get_priority(policy_entry_t *policy,
+ policy_priority_t prio)
+{
+ u_int32_t priority = PRIO_BASE;
+ switch (prio)
+ {
+ case POLICY_PRIORITY_FALLBACK:
+ priority <<= 1;
+ /* fall-through */
+ case POLICY_PRIORITY_ROUTED:
+ priority <<= 1;
+ /* fall-through */
+ case POLICY_PRIORITY_DEFAULT:
+ break;
+ }
+ /* calculate priority based on selector size, small size = high prio */
+ priority -= policy->sel.prefixlen_s;
+ priority -= policy->sel.prefixlen_d;
+ priority <<= 2; /* make some room for the two flags */
+ priority += policy->sel.sport_mask || policy->sel.dport_mask ? 0 : 2;
+ priority += policy->sel.proto ? 0 : 1;
+ return priority;
+}
/**
- * convert the general ipsec mode to the one defined in xfrm.h
+ * Convert the general ipsec mode to the one defined in xfrm.h
*/
static u_int8_t mode2kernel(ipsec_mode_t mode)
{
@@ -382,7 +623,7 @@ static u_int8_t mode2kernel(ipsec_mode_t mode)
}
/**
- * convert a host_t to a struct xfrm_address
+ * Convert a host_t to a struct xfrm_address
*/
static void host2xfrm(host_t *host, xfrm_address_t *xfrm)
{
@@ -391,7 +632,7 @@ static void host2xfrm(host_t *host, xfrm_address_t *xfrm)
}
/**
- * convert a struct xfrm_address to a host_t
+ * Convert a struct xfrm_address to a host_t
*/
static host_t* xfrm2host(int family, xfrm_address_t *xfrm, u_int16_t port)
{
@@ -412,7 +653,7 @@ static host_t* xfrm2host(int family, xfrm_address_t *xfrm, u_int16_t port)
}
/**
- * convert a traffic selector address range to subnet and its mask.
+ * Convert a traffic selector address range to subnet and its mask.
*/
static void ts2subnet(traffic_selector_t* ts,
xfrm_address_t *net, u_int8_t *mask)
@@ -427,12 +668,12 @@ static void ts2subnet(traffic_selector_t* ts,
}
/**
- * convert a traffic selector port range to port/portmask
+ * Convert a traffic selector port range to port/portmask
*/
static void ts2ports(traffic_selector_t* ts,
u_int16_t *port, u_int16_t *mask)
{
- /* linux does not seem to accept complex portmasks. Only
+ /* Linux does not seem to accept complex portmasks. Only
* any or a specific port is allowed. We set to any, if we have
* a port range, or to a specific, if we have one port only.
*/
@@ -454,7 +695,7 @@ static void ts2ports(traffic_selector_t* ts,
}
/**
- * convert a pair of traffic_selectors to a xfrm_selector
+ * Convert a pair of traffic_selectors to an xfrm_selector
*/
static struct xfrm_selector ts2selector(traffic_selector_t *src,
traffic_selector_t *dst)
@@ -476,7 +717,7 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src,
}
/**
- * convert a xfrm_selector to a src|dst traffic_selector
+ * Convert an xfrm_selector to a src|dst traffic_selector
*/
static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
{
@@ -525,16 +766,17 @@ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
}
/**
- * process a XFRM_MSG_ACQUIRE from kernel
+ * Process a XFRM_MSG_ACQUIRE from kernel
*/
-static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
+static void process_acquire(private_kernel_netlink_ipsec_t *this,
+ struct nlmsghdr *hdr)
{
- u_int32_t reqid = 0;
- int proto = 0;
- traffic_selector_t *src_ts, *dst_ts;
struct xfrm_user_acquire *acquire;
struct rtattr *rta;
size_t rtasize;
+ traffic_selector_t *src_ts, *dst_ts;
+ u_int32_t reqid = 0;
+ int proto = 0;
acquire = (struct xfrm_user_acquire*)NLMSG_DATA(hdr);
rta = XFRM_RTA(hdr, struct xfrm_user_acquire);
@@ -549,7 +791,6 @@ static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghd
if (rta->rta_type == XFRMA_TMPL)
{
struct xfrm_user_tmpl* tmpl;
-
tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rta);
reqid = tmpl->reqid;
proto = tmpl->id.proto;
@@ -574,13 +815,14 @@ static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghd
}
/**
- * process a XFRM_MSG_EXPIRE from kernel
+ * Process a XFRM_MSG_EXPIRE from kernel
*/
-static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
+static void process_expire(private_kernel_netlink_ipsec_t *this,
+ struct nlmsghdr *hdr)
{
- u_int8_t protocol;
- u_int32_t spi, reqid;
struct xfrm_user_expire *expire;
+ u_int32_t spi, reqid;
+ u_int8_t protocol;
expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr);
protocol = expire->state.id.proto;
@@ -601,17 +843,18 @@ static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr
}
/**
- * process a XFRM_MSG_MIGRATE from kernel
+ * Process a XFRM_MSG_MIGRATE from kernel
*/
-static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
+static void process_migrate(private_kernel_netlink_ipsec_t *this,
+ struct nlmsghdr *hdr)
{
+ struct xfrm_userpolicy_id *policy_id;
+ struct rtattr *rta;
+ size_t rtasize;
traffic_selector_t *src_ts, *dst_ts;
host_t *local = NULL, *remote = NULL;
host_t *old_src = NULL, *old_dst = NULL;
host_t *new_src = NULL, *new_dst = NULL;
- struct xfrm_userpolicy_id *policy_id;
- struct rtattr *rta;
- size_t rtasize;
u_int32_t reqid = 0;
policy_dir_t dir;
@@ -650,7 +893,7 @@ static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghd
new_dst = xfrm2host(migrate->new_family, &migrate->new_daddr, 0);
reqid = migrate->reqid;
DBG2(DBG_KNL, " migrate %H...%H to %H...%H, reqid {%u}",
- old_src, old_dst, new_src, new_dst, reqid);
+ old_src, old_dst, new_src, new_dst, reqid);
DESTROY_IF(old_src);
DESTROY_IF(old_dst);
DESTROY_IF(new_src);
@@ -674,14 +917,13 @@ static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghd
}
/**
- * process a XFRM_MSG_MAPPING from kernel
+ * Process a XFRM_MSG_MAPPING from kernel
*/
static void process_mapping(private_kernel_netlink_ipsec_t *this,
struct nlmsghdr *hdr)
{
- u_int32_t spi, reqid;
struct xfrm_user_mapping *mapping;
- host_t *host;
+ u_int32_t spi, reqid;
mapping = (struct xfrm_user_mapping*)NLMSG_DATA(hdr);
spi = mapping->id.spi;
@@ -691,6 +933,7 @@ static void process_mapping(private_kernel_netlink_ipsec_t *this,
if (mapping->id.proto == IPPROTO_ESP)
{
+ host_t *host;
host = xfrm2host(mapping->id.family, &mapping->new_saddr,
mapping->new_sport);
if (host)
@@ -757,7 +1000,8 @@ static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this)
process_mapping(this, hdr);
break;
default:
- DBG1(DBG_KNL, "received unknown event from xfrm event socket: %d", hdr->nlmsg_type);
+ DBG1(DBG_KNL, "received unknown event from xfrm event "
+ "socket: %d", hdr->nlmsg_type);
break;
}
hdr = NLMSG_NEXT(hdr, len);
@@ -769,8 +1013,8 @@ static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this)
* Get an SPI for a specific protocol from the kernel.
*/
static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this,
- host_t *src, host_t *dst, u_int8_t proto, u_int32_t min, u_int32_t max,
- u_int32_t reqid, u_int32_t *spi)
+ host_t *src, host_t *dst, u_int8_t proto, u_int32_t min, u_int32_t max,
+ u_int32_t reqid, u_int32_t *spi)
{
netlink_buf_t request;
struct nlmsghdr *hdr, *out;
@@ -811,7 +1055,6 @@ static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this,
case NLMSG_ERROR:
{
struct nlmsgerr *err = NLMSG_DATA(hdr);
-
DBG1(DBG_KNL, "allocating SPI failed: %s (%d)",
strerror(-err->error), -err->error);
break;
@@ -843,14 +1086,13 @@ METHOD(kernel_ipsec_t, get_spi, status_t,
DBG2(DBG_KNL, "getting SPI for reqid {%u}", reqid);
if (get_spi_internal(this, src, dst, protocol,
- 0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS)
+ 0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS)
{
DBG1(DBG_KNL, "unable to get SPI for reqid {%u}", reqid);
return FAILED;
}
DBG2(DBG_KNL, "got SPI %.8x for reqid {%u}", ntohl(*spi), reqid);
-
return SUCCESS;
}
@@ -862,8 +1104,8 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
DBG2(DBG_KNL, "getting CPI for reqid {%u}", reqid);
- if (get_spi_internal(this, src, dst,
- IPPROTO_COMP, 0x100, 0xEFFF, reqid, &received_spi) != SUCCESS)
+ if (get_spi_internal(this, src, dst, IPPROTO_COMP,
+ 0x100, 0xEFFF, reqid, &received_spi) != SUCCESS)
{
DBG1(DBG_KNL, "unable to get CPI for reqid {%u}", reqid);
return FAILED;
@@ -872,7 +1114,6 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
*cpi = htons((u_int16_t)ntohl(received_spi));
DBG2(DBG_KNL, "got CPI %.4x for reqid {%u}", ntohs(*cpi), reqid);
-
return SUCCESS;
}
@@ -896,9 +1137,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
if (ipcomp != IPCOMP_NONE && cpi != 0)
{
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);
+ 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);
ipcomp = IPCOMP_NONE;
/* use transport mode ESP SA, IPComp uses tunnel mode */
mode = MODE_TRANSPORT;
@@ -908,8 +1149,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
if (mark.value)
{
- DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u} "
- "(mark %u/0x%8x)", ntohl(spi), reqid, mark.value, mark.mask);
+ DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u} (mark "
+ "%u/0x%8x)", ntohl(spi), reqid, mark.value, mark.mask);
}
else
{
@@ -990,7 +1231,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
encryption_algorithm_names, enc_alg, enc_key.len * 8);
rthdr->rta_type = XFRMA_ALG_AEAD;
- rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_key.len);
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) +
+ enc_key.len);
hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
if (hdr->nlmsg_len > sizeof(request))
{
@@ -1039,6 +1281,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
if (int_alg != AUTH_UNDEFINED)
{
+ u_int trunc_len = 0;
+
alg_name = lookup_algorithm(integrity_algs, int_alg);
if (alg_name == NULL)
{
@@ -1049,14 +1293,29 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
DBG2(DBG_KNL, " using integrity algorithm %N with key size %d",
integrity_algorithm_names, int_alg, int_key.len * 8);
- if (int_alg == AUTH_HMAC_SHA2_256_128)
+ switch (int_alg)
+ {
+ case AUTH_HMAC_MD5_128:
+ case AUTH_HMAC_SHA2_256_128:
+ trunc_len = 128;
+ break;
+ case AUTH_HMAC_SHA1_160:
+ trunc_len = 160;
+ break;
+ default:
+ break;
+ }
+
+ if (trunc_len)
{
struct xfrm_algo_auth* algo;
/* the kernel uses SHA256 with 96 bit truncation by default,
- * use specified truncation size supported by newer kernels */
+ * use specified truncation size supported by newer kernels.
+ * also use this for untruncated MD5 and SHA1. */
rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC;
- rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) + int_key.len);
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) +
+ int_key.len);
hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
if (hdr->nlmsg_len > sizeof(request))
@@ -1066,7 +1325,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr);
algo->alg_key_len = int_key.len * 8;
- algo->alg_trunc_len = 128;
+ algo->alg_trunc_len = trunc_len;
strcpy(algo->alg_name, alg_name);
memcpy(algo->alg_key, int_key.ptr, int_key.len);
}
@@ -1137,14 +1396,15 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
tmpl->encap_dport = htons(dst->get_port(dst));
memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
/* encap_oa could probably be derived from the
- * traffic selectors [rfc4306, p39]. In the netlink kernel implementation
- * pluto does the same as we do here but it uses encap_oa in the
- * pfkey implementation. BUT as /usr/src/linux/net/key/af_key.c indicates
- * the kernel ignores it anyway
+ * traffic selectors [rfc4306, p39]. In the netlink kernel
+ * implementation pluto does the same as we do here but it uses
+ * encap_oa in the pfkey implementation.
+ * BUT as /usr/src/linux/net/key/af_key.c indicates the kernel ignores
+ * it anyway
* -> does that mean that NAT-T encap doesn't work in transport mode?
* No. The reason the kernel ignores NAT-OA is that it recomputes
- * (or, rather, just ignores) the checksum. If packets pass
- * the IPsec checks it marks them "checksum ok" so OA isn't needed. */
+ * (or, rather, just ignores) the checksum. If packets pass the IPsec
+ * checks it marks them "checksum ok" so OA isn't needed. */
rthdr = XFRM_RTA_NEXT(rthdr);
}
@@ -1207,10 +1467,13 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
/* bmp_len contains number uf __u32's */
replay->bmp_len = this->replay_bmp;
replay->replay_window = this->replay_window;
+ DBG2(DBG_KNL, " using replay window of %u bytes",
+ this->replay_window);
rthdr = XFRM_RTA_NEXT(rthdr);
if (esn)
{
+ DBG2(DBG_KNL, " using extended sequence numbers (ESN)");
sa->flags |= XFRM_STATE_ESN;
}
}
@@ -1261,7 +1524,7 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this,
memset(&request, 0, sizeof(request));
DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x",
- ntohl(spi));
+ ntohl(spi));
hdr = (struct nlmsghdr*)request;
hdr->nlmsg_flags = NLM_F_REQUEST;
@@ -1291,8 +1554,9 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this,
case NLMSG_ERROR:
{
struct nlmsgerr *err = NLMSG_DATA(hdr);
- DBG1(DBG_KNL, "querying replay state from SAD entry failed: %s (%d)",
- strerror(-err->error), -err->error);
+ DBG1(DBG_KNL, "querying replay state from SAD entry "
+ "failed: %s (%d)", strerror(-err->error),
+ -err->error);
break;
}
default:
@@ -1500,7 +1764,8 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
}
else
{
- DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi));
+ DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x",
+ ntohl(spi));
}
return FAILED;
}
@@ -1596,12 +1861,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
/* delete the old SA (without affecting the IPComp SA) */
if (del_sa(this, src, dst, spi, protocol, 0, mark) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", ntohl(spi));
+ DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x",
+ ntohl(spi));
goto failed;
}
DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
- ntohl(spi), src, dst, new_src, new_dst);
+ ntohl(spi), src, dst, new_src, new_dst);
/* copy over the SA from out to request */
hdr = (struct nlmsghdr*)request;
memcpy(hdr, out, min(out->nlmsg_len, sizeof(request)));
@@ -1695,7 +1961,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
else
{
DBG1(DBG_KNL, "unable to copy replay state from old SAD entry "
- "with SPI %.8x", ntohl(spi));
+ "with SPI %.8x", ntohl(spi));
}
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
@@ -1709,77 +1975,62 @@ failed:
free(replay);
free(replay_esn);
memwipe(out, len);
+ memwipe(request, sizeof(request));
free(out);
return status;
}
-METHOD(kernel_ipsec_t, add_policy, status_t,
- private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
- traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
- policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
- mark_t mark, bool routed)
+METHOD(kernel_ipsec_t, flush_sas, status_t,
+ private_kernel_netlink_ipsec_t *this)
{
- policy_entry_t *current, *policy;
- bool found = FALSE;
netlink_buf_t request;
- struct xfrm_userpolicy_info *policy_info;
struct nlmsghdr *hdr;
- int i;
+ struct xfrm_usersa_flush *flush;
- /* create a policy */
- policy = malloc_thing(policy_entry_t);
- memset(policy, 0, sizeof(policy_entry_t));
- policy->sel = ts2selector(src_ts, dst_ts);
- policy->mark = mark.value & mark.mask;
- policy->direction = direction;
+ memset(&request, 0, sizeof(request));
- /* find the policy, which matches EXACTLY */
- this->mutex->lock(this->mutex);
- current = this->policies->get(this->policies, policy);
- if (current)
- {
- /* use existing policy */
- current->refcount++;
- if (mark.value)
- {
- DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%8x) "
- "already exists, increasing refcount",
- src_ts, dst_ts, policy_dir_names, direction,
- mark.value, mark.mask);
- }
- else
- {
- DBG2(DBG_KNL, "policy %R === %R %N "
- "already exists, increasing refcount",
- src_ts, dst_ts, policy_dir_names, direction);
- }
- free(policy);
- policy = current;
- found = TRUE;
- }
- else
- { /* apply the new one, if we have no such policy */
- this->policies->put(this->policies, policy, policy);
- policy->refcount = 1;
- }
+ DBG2(DBG_KNL, "flushing all SAD entries");
- if (mark.value)
- {
- DBG2(DBG_KNL, "adding policy %R === %R %N (mark %u/0x%8x)",
- src_ts, dst_ts, policy_dir_names, direction,
- mark.value, mark.mask);
- }
- else
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ hdr->nlmsg_type = XFRM_MSG_FLUSHSA;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
+
+ flush = (struct xfrm_usersa_flush*)NLMSG_DATA(hdr);
+ flush->proto = IPSEC_PROTO_ANY;
+
+ if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
- DBG2(DBG_KNL, "adding policy %R === %R %N",
- src_ts, dst_ts, policy_dir_names, direction);
+ DBG1(DBG_KNL, "unable to flush SAD entries");
+ return FAILED;
}
+ return SUCCESS;
+}
+
+/**
+ * Add or update a policy in the kernel.
+ *
+ * Note: The mutex has to be locked when entering this function
+ * and is unlocked here in any case.
+ */
+static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
+ policy_entry_t *policy, policy_sa_t *mapping, bool update)
+{
+ netlink_buf_t request;
+ policy_entry_t clone;
+ ipsec_sa_t *ipsec = mapping->sa;
+ struct xfrm_userpolicy_info *policy_info;
+ struct nlmsghdr *hdr;
+ int i;
+
+ /* clone the policy so we are able to check it out again later */
+ memcpy(&clone, policy, sizeof(policy_entry_t));
memset(&request, 0, sizeof(request));
hdr = (struct nlmsghdr*)request;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
- hdr->nlmsg_type = found ? XFRM_MSG_UPDPOLICY : XFRM_MSG_NEWPOLICY;
+ hdr->nlmsg_type = update ? XFRM_MSG_UPDPOLICY : XFRM_MSG_NEWPOLICY;
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
policy_info = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr);
@@ -1787,18 +2038,10 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
policy_info->dir = policy->direction;
/* calculate priority based on selector size, small size = high prio */
- policy_info->priority = routed ? PRIO_LOW : PRIO_HIGH;
- policy_info->priority -= policy->sel.prefixlen_s;
- policy_info->priority -= policy->sel.prefixlen_d;
- policy_info->priority <<= 2; /* make some room for the two flags */
- policy_info->priority += policy->sel.sport_mask ||
- policy->sel.dport_mask ? 0 : 2;
- policy_info->priority += policy->sel.proto ? 0 : 1;
-
- policy_info->action = type != POLICY_DROP ? XFRM_POLICY_ALLOW
- : XFRM_POLICY_BLOCK;
+ policy_info->priority = mapping->priority;
+ policy_info->action = mapping->type != POLICY_DROP ? XFRM_POLICY_ALLOW
+ : XFRM_POLICY_BLOCK;
policy_info->share = XFRM_SHARE_ANY;
- this->mutex->unlock(this->mutex);
/* policies don't expire */
policy_info->lft.soft_byte_limit = XFRM_INF;
@@ -1812,18 +2055,18 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info);
- if (type == POLICY_IPSEC)
+ if (mapping->type == POLICY_IPSEC)
{
struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
struct {
u_int8_t proto;
bool use;
} protos[] = {
- { IPPROTO_COMP, sa->ipcomp.transform != IPCOMP_NONE },
- { IPPROTO_ESP, sa->esp.use },
- { IPPROTO_AH, sa->ah.use },
+ { IPPROTO_COMP, ipsec->cfg.ipcomp.transform != IPCOMP_NONE },
+ { IPPROTO_ESP, ipsec->cfg.esp.use },
+ { IPPROTO_AH, ipsec->cfg.ah.use },
};
- ipsec_mode_t proto_mode = sa->mode;
+ ipsec_mode_t proto_mode = ipsec->cfg.mode;
rthdr->rta_type = XFRMA_TMPL;
rthdr->rta_len = 0; /* actual length is set below */
@@ -1839,21 +2082,22 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
hdr->nlmsg_len += RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl)));
if (hdr->nlmsg_len > sizeof(request))
{
+ this->mutex->unlock(this->mutex);
return FAILED;
}
- tmpl->reqid = sa->reqid;
+ tmpl->reqid = ipsec->cfg.reqid;
tmpl->id.proto = protos[i].proto;
tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
tmpl->mode = mode2kernel(proto_mode);
tmpl->optional = protos[i].proto == IPPROTO_COMP &&
- direction != POLICY_OUT;
- tmpl->family = src->get_family(src);
+ policy->direction != POLICY_OUT;
+ tmpl->family = ipsec->src->get_family(ipsec->src);
if (proto_mode == MODE_TUNNEL)
{ /* only for tunnel mode */
- host2xfrm(src, &tmpl->saddr);
- host2xfrm(dst, &tmpl->id.daddr);
+ host2xfrm(ipsec->src, &tmpl->saddr);
+ host2xfrm(ipsec->dst, &tmpl->id.daddr);
}
tmpl++;
@@ -1865,7 +2109,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
rthdr = XFRM_RTA_NEXT(rthdr);
}
- if (mark.value)
+ if (ipsec->mark.value)
{
struct xfrm_mark *mrk;
@@ -1875,71 +2119,110 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
if (hdr->nlmsg_len > sizeof(request))
{
+ this->mutex->unlock(this->mutex);
return FAILED;
}
mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
- mrk->v = mark.value;
- mrk->m = mark.mask;
+ mrk->v = ipsec->mark.value;
+ mrk->m = ipsec->mark.mask;
}
+ this->mutex->unlock(this->mutex);
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to add policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
return FAILED;
}
+ /* find the policy again */
+ this->mutex->lock(this->mutex);
+ policy = this->policies->get(this->policies, &clone);
+ if (!policy ||
+ policy->used_by->find_first(policy->used_by,
+ NULL, (void**)&mapping) != SUCCESS)
+ { /* policy or mapping is already gone, ignore */
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+ }
+
/* install a route, if:
- * - we are NOT updating a policy
* - this is a forward policy (to just get one for each child)
* - we are in tunnel/BEET mode
* - routing is not disabled via strongswan.conf
*/
- if (policy->route == NULL && direction == POLICY_FWD &&
- sa->mode != MODE_TRANSPORT && this->install_routes)
+ if (policy->direction == POLICY_FWD &&
+ ipsec->cfg.mode != MODE_TRANSPORT && this->install_routes)
{
route_entry_t *route = malloc_thing(route_entry_t);
+ policy_sa_fwd_t *fwd = (policy_sa_fwd_t*)mapping;
if (hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface,
- dst_ts, &route->src_ip) == SUCCESS)
+ fwd->dst_ts, &route->src_ip) == SUCCESS)
{
- /* get the nexthop to src (src as we are in POLICY_FWD).*/
+ /* get the nexthop to src (src as we are in POLICY_FWD) */
route->gateway = hydra->kernel_interface->get_nexthop(
- hydra->kernel_interface, src);
+ hydra->kernel_interface, ipsec->src);
/* install route via outgoing interface */
route->if_name = hydra->kernel_interface->get_interface(
- hydra->kernel_interface, dst);
+ hydra->kernel_interface, ipsec->dst);
route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len);
route->prefixlen = policy->sel.prefixlen_s;
- if (route->if_name)
+ if (!route->if_name)
+ {
+ this->mutex->unlock(this->mutex);
+ route_entry_destroy(route);
+ return SUCCESS;
+ }
+
+ if (policy->route)
{
- DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s",
- src_ts, route->gateway, route->src_ip, route->if_name);
- switch (hydra->kernel_interface->add_route(
- hydra->kernel_interface, route->dst_net,
- route->prefixlen, route->gateway,
- route->src_ip, route->if_name))
+ route_entry_t *old = policy->route;
+ if (route_entry_equals(old, route))
+ { /* keep previously installed route. since it might have
+ * still been removed by an address change, we install it
+ * again but ignore the result */
+ hydra->kernel_interface->add_route(hydra->kernel_interface,
+ route->dst_net, route->prefixlen, route->gateway,
+ route->src_ip, route->if_name);
+ this->mutex->unlock(this->mutex);
+ route_entry_destroy(route);
+ return SUCCESS;
+ }
+ /* uninstall previously installed route */
+ if (hydra->kernel_interface->del_route(hydra->kernel_interface,
+ old->dst_net, old->prefixlen, old->gateway,
+ old->src_ip, old->if_name) != SUCCESS)
{
- default:
- DBG1(DBG_KNL, "unable to install source route for %H",
- route->src_ip);
- /* FALL */
- case ALREADY_DONE:
- /* route exists, do not uninstall */
- route_entry_destroy(route);
- break;
- case SUCCESS:
- /* cache the installed route */
- policy->route = route;
- break;
+ DBG1(DBG_KNL, "error uninstalling route installed with "
+ "policy %R === %R %N", fwd->src_ts,
+ fwd->dst_ts, policy_dir_names,
+ policy->direction);
}
+ route_entry_destroy(old);
+ policy->route = NULL;
}
- else
+
+ DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s",
+ fwd->src_ts, route->gateway, route->src_ip, route->if_name);
+ switch (hydra->kernel_interface->add_route(
+ hydra->kernel_interface, route->dst_net,
+ route->prefixlen, route->gateway,
+ route->src_ip, route->if_name))
{
- route_entry_destroy(route);
+ default:
+ DBG1(DBG_KNL, "unable to install source route for %H",
+ route->src_ip);
+ /* FALL */
+ case ALREADY_DONE:
+ /* route exists, do not uninstall */
+ route_entry_destroy(route);
+ break;
+ case SUCCESS:
+ /* cache the installed route */
+ policy->route = route;
+ break;
}
}
else
@@ -1947,6 +2230,110 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
free(route);
}
}
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+}
+
+METHOD(kernel_ipsec_t, add_policy, status_t,
+ private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
+ policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
+ mark_t mark, policy_priority_t priority)
+{
+ policy_entry_t *policy, *current;
+ policy_sa_t *assigned_sa, *current_sa;
+ enumerator_t *enumerator;
+ bool found = FALSE, update = TRUE;
+
+ /* create a policy */
+ INIT(policy,
+ .sel = ts2selector(src_ts, dst_ts),
+ .mark = mark.value & mark.mask,
+ .direction = direction,
+ );
+
+ /* find the policy, which matches EXACTLY */
+ this->mutex->lock(this->mutex);
+ current = this->policies->get(this->policies, policy);
+ if (current)
+ {
+ /* use existing policy */
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%8x) "
+ "already exists, increasing refcount",
+ src_ts, dst_ts, policy_dir_names, direction,
+ mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "policy %R === %R %N "
+ "already exists, increasing refcount",
+ src_ts, dst_ts, policy_dir_names, direction);
+ }
+ policy_entry_destroy(this, policy);
+ policy = current;
+ found = TRUE;
+ }
+ else
+ { /* use the new one, if we have no such policy */
+ policy->used_by = linked_list_create();
+ this->policies->put(this->policies, policy, policy);
+ }
+
+ /* cache the assigned IPsec SA */
+ assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts,
+ dst_ts, mark, sa);
+ assigned_sa->priority = get_priority(policy, priority);
+
+ if (this->policy_history)
+ { /* insert the SA according to its priority */
+ enumerator = policy->used_by->create_enumerator(policy->used_by);
+ while (enumerator->enumerate(enumerator, (void**)&current_sa))
+ {
+ if (current_sa->priority >= assigned_sa->priority)
+ {
+ break;
+ }
+ update = FALSE;
+ }
+ policy->used_by->insert_before(policy->used_by, enumerator,
+ assigned_sa);
+ enumerator->destroy(enumerator);
+ }
+ else
+ { /* simply insert it last and only update if it is not installed yet */
+ policy->used_by->insert_last(policy->used_by, assigned_sa);
+ update = !found;
+ }
+
+ if (!update)
+ { /* we don't update the policy if the priority is lower than that of
+ * the currently installed one */
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+ }
+
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "%s policy %R === %R %N (mark %u/0x%8x)",
+ found ? "updating" : "adding", src_ts, dst_ts,
+ policy_dir_names, direction, mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "%s policy %R === %R %N",
+ found ? "updating" : "adding", src_ts, dst_ts,
+ policy_dir_names, direction);
+ }
+
+ if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unable to %s policy %R === %R %N",
+ found ? "update" : "add", src_ts, dst_ts,
+ policy_dir_names, direction);
+ return FAILED;
+ }
return SUCCESS;
}
@@ -2018,7 +2405,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
{
struct nlmsgerr *err = NLMSG_DATA(hdr);
DBG1(DBG_KNL, "querying policy failed: %s (%d)",
- strerror(-err->error), -err->error);
+ strerror(-err->error), -err->error);
break;
}
default:
@@ -2055,14 +2442,17 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
- bool unrouted)
+ traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ mark_t mark, policy_priority_t prio)
{
- policy_entry_t *current, policy, *to_delete = NULL;
- route_entry_t *route;
+ policy_entry_t *current, policy;
+ enumerator_t *enumerator;
+ policy_sa_t *mapping;
netlink_buf_t request;
struct nlmsghdr *hdr;
struct xfrm_userpolicy_id *policy_id;
+ bool is_installed = TRUE;
+ u_int32_t priority;
if (mark.value)
{
@@ -2085,21 +2475,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)
- {
- to_delete = current;
- if (--to_delete->refcount > 0)
- {
- /* is used by more SAs, keep in kernel */
- DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
- this->mutex->unlock(this->mutex);
- return SUCCESS;
- }
- /* remove if last reference */
- this->policies->remove(this->policies, to_delete);
- }
- this->mutex->unlock(this->mutex);
- if (!to_delete)
+ if (!current)
{
if (mark.value)
{
@@ -2112,9 +2488,65 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found",
src_ts, dst_ts, policy_dir_names, direction);
}
+ this->mutex->unlock(this->mutex);
return NOT_FOUND;
}
+ if (this->policy_history)
+ { /* remove mapping to SA by reqid and priority */
+ priority = get_priority(current, prio);
+ enumerator = current->used_by->create_enumerator(current->used_by);
+ while (enumerator->enumerate(enumerator, (void**)&mapping))
+ {
+ if (reqid == mapping->sa->cfg.reqid &&
+ priority == mapping->priority)
+ {
+ current->used_by->remove_at(current->used_by, enumerator);
+ policy_sa_destroy(mapping, &direction, this);
+ break;
+ }
+ is_installed = FALSE;
+ }
+ enumerator->destroy(enumerator);
+ }
+ else
+ { /* remove one of the SAs but don't update the policy */
+ current->used_by->remove_last(current->used_by, (void**)&mapping);
+ policy_sa_destroy(mapping, &direction, this);
+ is_installed = FALSE;
+ }
+
+ if (current->used_by->get_count(current->used_by) > 0)
+ { /* policy is used by more SAs, keep in kernel */
+ DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
+ if (!is_installed)
+ { /* no need to update as the policy was not installed for this SA */
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+ }
+
+ if (mark.value)
+ {
+ DBG2(DBG_KNL, "updating policy %R === %R %N (mark %u/0x%8x)",
+ src_ts, dst_ts, policy_dir_names, direction,
+ mark.value, mark.mask);
+ }
+ else
+ {
+ DBG2(DBG_KNL, "updating policy %R === %R %N",
+ src_ts, dst_ts, policy_dir_names, direction);
+ }
+
+ current->used_by->get_first(current->used_by, (void**)&mapping);
+ if (add_policy_internal(this, current, mapping, TRUE) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unable to update policy %R === %R %N",
+ src_ts, dst_ts, policy_dir_names, direction);
+ return FAILED;
+ }
+ return SUCCESS;
+ }
+
memset(&request, 0, sizeof(request));
hdr = (struct nlmsghdr*)request;
@@ -2123,7 +2555,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id));
policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr);
- policy_id->sel = to_delete->sel;
+ policy_id->sel = current->sel;
policy_id->dir = direction;
if (mark.value)
@@ -2136,6 +2568,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
if (hdr->nlmsg_len > sizeof(request))
{
+ this->mutex->unlock(this->mutex);
return FAILED;
}
@@ -2144,15 +2577,29 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
mrk->m = mark.mask;
}
- route = to_delete->route;
- free(to_delete);
+ if (current->route)
+ {
+ route_entry_t *route = current->route;
+ if (hydra->kernel_interface->del_route(hydra->kernel_interface,
+ route->dst_net, route->prefixlen, route->gateway,
+ route->src_ip, route->if_name) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "error uninstalling route installed with "
+ "policy %R === %R %N", src_ts, dst_ts,
+ policy_dir_names, direction);
+ }
+ }
+
+ this->policies->remove(this->policies, current);
+ policy_entry_destroy(this, current);
+ this->mutex->unlock(this->mutex);
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
if (mark.value)
{
DBG1(DBG_KNL, "unable to delete policy %R === %R %N "
- "(mark %u/0x%8x)", src_ts, dst_ts, policy_dir_names,
+ "(mark %u/0x%8x)", src_ts, dst_ts, policy_dir_names,
direction, mark.value, mark.mask);
}
else
@@ -2162,22 +2609,36 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
}
return FAILED;
}
+ return SUCCESS;
+}
+
+METHOD(kernel_ipsec_t, flush_policies, status_t,
+ private_kernel_netlink_ipsec_t *this)
+{
+ netlink_buf_t request;
+ struct nlmsghdr *hdr;
+
+ memset(&request, 0, sizeof(request));
- if (route)
+ DBG2(DBG_KNL, "flushing all policies from SPD");
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ hdr->nlmsg_type = XFRM_MSG_FLUSHPOLICY;
+ hdr->nlmsg_len = NLMSG_LENGTH(0); /* no data associated */
+
+ /* by adding an rtattr of type XFRMA_POLICY_TYPE we could restrict this
+ * to main or sub policies (default is main) */
+
+ if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
- if (hydra->kernel_interface->del_route(hydra->kernel_interface,
- route->dst_net, route->prefixlen, route->gateway,
- route->src_ip, route->if_name) != SUCCESS)
- {
- DBG1(DBG_KNL, "error uninstalling route installed with "
- "policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
- }
- route_entry_destroy(route);
+ DBG1(DBG_KNL, "unable to flush SPD entries");
+ return FAILED;
}
return SUCCESS;
}
+
METHOD(kernel_ipsec_t, bypass_socket, bool,
private_kernel_netlink_ipsec_t *this, int fd, int family)
{
@@ -2206,14 +2667,14 @@ METHOD(kernel_ipsec_t, bypass_socket, bool,
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
- strerror(errno));
+ strerror(errno));
return FALSE;
}
policy.dir = XFRM_POLICY_IN;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
- strerror(errno));
+ strerror(errno));
return FALSE;
}
return TRUE;
@@ -2237,10 +2698,11 @@ METHOD(kernel_ipsec_t, destroy, void,
enumerator = this->policies->create_enumerator(this->policies);
while (enumerator->enumerate(enumerator, &policy, &policy))
{
- free(policy);
+ policy_entry_destroy(this, policy);
}
enumerator->destroy(enumerator);
this->policies->destroy(this->policies);
+ this->sas->destroy(this->sas);
this->mutex->destroy(this->mutex);
free(this);
}
@@ -2263,16 +2725,21 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
.update_sa = _update_sa,
.query_sa = _query_sa,
.del_sa = _del_sa,
+ .flush_sas = _flush_sas,
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
+ .flush_policies = _flush_policies,
.bypass_socket = _bypass_socket,
.destroy = _destroy,
},
},
.policies = hashtable_create((hashtable_hash_t)policy_hash,
(hashtable_equals_t)policy_equals, 32),
+ .sas = hashtable_create((hashtable_hash_t)ipsec_sa_hash,
+ (hashtable_equals_t)ipsec_sa_equals, 32),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .policy_history = TRUE,
.install_routes = lib->settings->get_bool(lib->settings,
"%s.install_routes", TRUE, hydra->daemon),
.replay_window = lib->settings->get_int(lib->settings,
@@ -2285,6 +2752,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
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;
}
/* disable lifetimes for allocated SPIs in kernel */
@@ -2321,8 +2790,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
destroy(this);
return NULL;
}
- this->job = callback_job_create((callback_job_cb_t)receive_events,
- this, NULL, NULL);
+ this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
lib->processor->queue_job(lib->processor, (job_t*)this->job);
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 8315ed310..cce0ff402 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
@@ -193,16 +193,16 @@ struct private_kernel_netlink_net_t {
*/
static int get_vip_refcount(private_kernel_netlink_net_t *this, host_t* ip)
{
- iterator_t *ifaces, *addrs;
+ enumerator_t *ifaces, *addrs;
iface_entry_t *iface;
addr_entry_t *addr;
int refcount = 0;
- ifaces = this->ifaces->create_iterator(this->ifaces, TRUE);
- while (ifaces->iterate(ifaces, (void**)&iface))
+ ifaces = this->ifaces->create_enumerator(this->ifaces);
+ while (ifaces->enumerate(ifaces, (void**)&iface))
{
- addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
- while (addrs->iterate(addrs, (void**)&addr))
+ addrs = iface->addrs->create_enumerator(iface->addrs);
+ while (addrs->enumerate(addrs, (void**)&addr))
{
if (addr->virtual && (iface->flags & IFF_UP) &&
ip->ip_equals(ip, addr->ip))
@@ -375,9 +375,13 @@ static void process_link(private_kernel_netlink_net_t *this,
{
if (current->ifindex == msg->ifi_index)
{
- /* we do not remove it, as an address may be added to a
- * "down" interface and we wan't to know that. */
- current->flags = msg->ifi_flags;
+ if (event)
+ {
+ update = TRUE;
+ DBG1(DBG_KNL, "interface %s deleted", current->ifname);
+ }
+ this->ifaces->remove_at(this->ifaces, enumerator);
+ iface_entry_destroy(current);
break;
}
}
@@ -904,7 +908,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
struct rtattr *rta;
size_t rtasize;
chunk_t rta_gtw, rta_src, rta_dst;
- u_int32_t rta_oif = 0;
+ u_int32_t rta_oif = 0, rta_table;
host_t *new_src, *new_gtw;
bool cont = FALSE;
uintptr_t table;
@@ -913,6 +917,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
msg = (struct rtmsg*)(NLMSG_DATA(current));
rta = RTM_RTA(msg);
rtasize = RTM_PAYLOAD(current);
+ rta_table = msg->rtm_table;
while (RTA_OK(rta, rtasize))
{
switch (rta->rta_type)
@@ -932,6 +937,14 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
rta_oif = *(u_int32_t*)RTA_DATA(rta);
}
break;
+#ifdef HAVE_RTA_TABLE
+ case RTA_TABLE:
+ if (RTA_PAYLOAD(rta) == sizeof(rta_table))
+ {
+ rta_table = *(u_int32_t*)RTA_DATA(rta);
+ }
+ break;
+#endif /* HAVE_RTA_TABLE*/
}
rta = RTA_NEXT(rta, rtasize);
}
@@ -942,7 +955,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
enumerator = this->rt_exclude->create_enumerator(this->rt_exclude);
while (enumerator->enumerate(enumerator, &table))
{
- if (table == msg->rtm_table)
+ if (table == rta_table)
{
cont = TRUE;
break;
@@ -954,7 +967,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
continue;
}
if (this->routing_table != 0 &&
- msg->rtm_table == this->routing_table)
+ rta_table == this->routing_table)
{ /* route is from our own ipsec routing table */
continue;
}
@@ -1529,7 +1542,7 @@ kernel_netlink_net_t *kernel_netlink_net_create()
return NULL;
}
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
- RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
+ RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK;
if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr)))
{
DBG1(DBG_KNL, "unable to bind RT event socket");
@@ -1537,8 +1550,8 @@ kernel_netlink_net_t *kernel_netlink_net_create()
return NULL;
}
- this->job = callback_job_create((callback_job_cb_t)receive_events,
- this, NULL, NULL);
+ this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
lib->processor->queue_job(lib->processor, (job_t*)this->job);
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 779466472..0eb00dadf 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c
@@ -39,13 +39,22 @@ METHOD(plugin_t, get_name, char*,
return "kernel-netlink";
}
+METHOD(plugin_t, get_features, int,
+ private_kernel_netlink_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(kernel_ipsec_register, kernel_netlink_ipsec_create),
+ PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
+ PLUGIN_CALLBACK(kernel_net_register, kernel_netlink_net_create),
+ PLUGIN_PROVIDE(CUSTOM, "kernel-net"),
+ };
+ *features = f;
+ return countof(f);
+}
+
METHOD(plugin_t, destroy, void,
private_kernel_netlink_plugin_t *this)
{
- hydra->kernel_interface->remove_ipsec_interface(hydra->kernel_interface,
- (kernel_ipsec_constructor_t)kernel_netlink_ipsec_create);
- hydra->kernel_interface->remove_net_interface(hydra->kernel_interface,
- (kernel_net_constructor_t)kernel_netlink_net_create);
free(this);
}
@@ -60,15 +69,11 @@ plugin_t *kernel_netlink_plugin_create()
.public = {
.plugin = {
.get_name = _get_name,
- .reload = (void*)return_false,
+ .get_features = _get_features,
.destroy = _destroy,
},
},
);
- hydra->kernel_interface->add_ipsec_interface(hydra->kernel_interface,
- (kernel_ipsec_constructor_t)kernel_netlink_ipsec_create);
- hydra->kernel_interface->add_net_interface(hydra->kernel_interface,
- (kernel_net_constructor_t)kernel_netlink_net_create);
return &this->public.plugin;
}
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
index c26fd2e51..dad3fb68e 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
@@ -61,11 +61,9 @@ struct private_netlink_socket_t {
*/
extern enum_name_t *xfrm_msg_names;
-/**
- * Implementation of netlink_socket_t.send
- */
-static status_t netlink_send(private_netlink_socket_t *this, struct nlmsghdr *in,
- struct nlmsghdr **out, size_t *out_len)
+METHOD(netlink_socket_t, netlink_send, status_t,
+ private_netlink_socket_t *this, struct nlmsghdr *in, struct nlmsghdr **out,
+ size_t *out_len)
{
int len, addr_len;
struct sockaddr_nl addr;
@@ -182,10 +180,8 @@ static status_t netlink_send(private_netlink_socket_t *this, struct nlmsghdr *in
return SUCCESS;
}
-/**
- * Implementation of netlink_socket_t.send_ack.
- */
-static status_t netlink_send_ack(private_netlink_socket_t *this, struct nlmsghdr *in)
+METHOD(netlink_socket_t, netlink_send_ack, status_t,
+ private_netlink_socket_t *this, struct nlmsghdr *in)
{
struct nlmsghdr *out, *hdr;
size_t len;
@@ -231,10 +227,8 @@ static status_t netlink_send_ack(private_netlink_socket_t *this, struct nlmsghdr
return FAILED;
}
-/**
- * Implementation of netlink_socket_t.destroy.
- */
-static void destroy(private_netlink_socket_t *this)
+METHOD(netlink_socket_t, destroy, void,
+ private_netlink_socket_t *this)
{
if (this->socket > 0)
{
@@ -249,22 +243,23 @@ static void destroy(private_netlink_socket_t *this)
*/
netlink_socket_t *netlink_socket_create(int protocol)
{
- private_netlink_socket_t *this = malloc_thing(private_netlink_socket_t);
+ private_netlink_socket_t *this;
struct sockaddr_nl addr;
- /* public functions */
- this->public.send = (status_t(*)(netlink_socket_t*,struct nlmsghdr*, struct nlmsghdr**, size_t*))netlink_send;
- this->public.send_ack = (status_t(*)(netlink_socket_t*,struct nlmsghdr*))netlink_send_ack;
- this->public.destroy = (void(*)(netlink_socket_t*))destroy;
-
- /* private members */
- this->seq = 200;
- this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ INIT(this,
+ .public = {
+ .send = _netlink_send,
+ .send_ack = _netlink_send_ack,
+ .destroy = _destroy,
+ },
+ .seq = 200,
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .protocol = protocol,
+ );
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
- this->protocol = protocol;
this->socket = socket(AF_NETLINK, SOCK_RAW, protocol);
if (this->socket < 0)
{
diff --git a/src/libhydra/plugins/kernel_pfkey/Makefile.in b/src/libhydra/plugins/kernel_pfkey/Makefile.in
index 251483017..14c924b6f 100644
--- a/src/libhydra/plugins/kernel_pfkey/Makefile.in
+++ b/src/libhydra/plugins/kernel_pfkey/Makefile.in
@@ -195,6 +195,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -203,6 +206,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -219,11 +223,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -267,6 +273,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
index b252b7092..da10edffe 100644
--- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
+++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2010 Tobias Brunner
+ * Copyright (C) 2008-2011 Tobias Brunner
* Copyright (C) 2008 Andreas Steffen
* Hochschule fuer Technik Rapperswil
*
@@ -58,6 +58,7 @@
#include <debug.h>
#include <utils/host.h>
#include <utils/linked_list.h>
+#include <utils/hashtable.h>
#include <threading/thread.h>
#include <threading/mutex.h>
#include <processing/jobs/callback_job.h>
@@ -99,8 +100,7 @@
#endif
/** default priority of installed policies */
-#define PRIO_LOW 1024
-#define PRIO_HIGH 512
+#define PRIO_BASE 512
#ifdef __APPLE__
/** from xnu/bsd/net/pfkeyv2.h */
@@ -163,6 +163,11 @@ struct private_kernel_pfkey_ipsec_t
linked_list_t *policies;
/**
+ * Hash table of IPsec SAs using policies (ipsec_sa_t)
+ */
+ hashtable_t *sas;
+
+ /**
* whether to install routes along policies
*/
bool install_routes;
@@ -199,19 +204,19 @@ typedef struct route_entry_t route_entry_t;
* installed routing entry
*/
struct route_entry_t {
- /** Name of the interface the route is bound to */
+ /** name of the interface the route is bound to */
char *if_name;
- /** Source ip of the route */
+ /** source ip of the route */
host_t *src_ip;
/** gateway for this route */
host_t *gateway;
- /** Destination net */
+ /** destination net */
chunk_t dst_net;
- /** Destination net prefixlen */
+ /** destination net prefixlen */
u_int8_t prefixlen;
};
@@ -227,57 +232,222 @@ static void route_entry_destroy(route_entry_t *this)
free(this);
}
+/**
+ * compare two route_entry_t objects
+ */
+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->equals(a->src_ip, b->src_ip) &&
+ a->gateway->equals(a->gateway, b->gateway) &&
+ chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen;
+}
+
+typedef struct ipsec_sa_t ipsec_sa_t;
+
+/**
+ * IPsec SA assigned to a policy.
+ */
+struct ipsec_sa_t {
+ /** Source address of this SA */
+ host_t *src;
+
+ /** Destination address of this SA */
+ host_t *dst;
+
+ /** Description of this SA */
+ ipsec_sa_cfg_t cfg;
+
+ /** Reference count for this SA */
+ refcount_t refcount;
+};
+
+/**
+ * Hash function for ipsec_sa_t objects
+ */
+static u_int ipsec_sa_hash(ipsec_sa_t *sa)
+{
+ return chunk_hash_inc(sa->src->get_address(sa->src),
+ chunk_hash_inc(sa->dst->get_address(sa->dst),
+ chunk_hash(chunk_from_thing(sa->cfg))));
+}
+
+/**
+ * Equality function for ipsec_sa_t objects
+ */
+static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa)
+{
+ return sa->src->ip_equals(sa->src, other_sa->src) &&
+ sa->dst->ip_equals(sa->dst, other_sa->dst) &&
+ memeq(&sa->cfg, &other_sa->cfg, sizeof(ipsec_sa_cfg_t));
+}
+
+/**
+ * Allocate or reference an IPsec SA object
+ */
+static ipsec_sa_t *ipsec_sa_create(private_kernel_pfkey_ipsec_t *this,
+ host_t *src, host_t *dst,
+ ipsec_sa_cfg_t *cfg)
+{
+ ipsec_sa_t *sa, *found;
+ INIT(sa,
+ .src = src,
+ .dst = dst,
+ .cfg = *cfg,
+ );
+ found = this->sas->get(this->sas, sa);
+ if (!found)
+ {
+ sa->src = src->clone(src);
+ sa->dst = dst->clone(dst);
+ this->sas->put(this->sas, sa, sa);
+ }
+ else
+ {
+ free(sa);
+ sa = found;
+ }
+ ref_get(&sa->refcount);
+ return sa;
+}
+
+/**
+ * Release and destroy an IPsec SA object
+ */
+static void ipsec_sa_destroy(private_kernel_pfkey_ipsec_t *this,
+ ipsec_sa_t *sa)
+{
+ if (ref_put(&sa->refcount))
+ {
+ this->sas->remove(this->sas, sa);
+ DESTROY_IF(sa->src);
+ DESTROY_IF(sa->dst);
+ free(sa);
+ }
+}
+
+typedef struct policy_sa_t policy_sa_t;
+typedef struct policy_sa_fwd_t policy_sa_fwd_t;
+
+/**
+ * Mapping between a policy and an IPsec SA.
+ */
+struct policy_sa_t {
+ /** Priority assigned to the policy when installed with this SA */
+ u_int32_t priority;
+
+ /** Type of the policy */
+ policy_type_t type;
+
+ /** Assigned SA */
+ ipsec_sa_t *sa;
+};
+
+/**
+ * For forward policies we also cache the traffic selectors in order to install
+ * the route.
+ */
+struct policy_sa_fwd_t {
+ /** Generic interface */
+ policy_sa_t generic;
+
+ /** Source traffic selector of this policy */
+ traffic_selector_t *src_ts;
+
+ /** Destination traffic selector of this policy */
+ traffic_selector_t *dst_ts;
+};
+
+/**
+ * Create a policy_sa(_fwd)_t object
+ */
+static policy_sa_t *policy_sa_create(private_kernel_pfkey_ipsec_t *this,
+ policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts, ipsec_sa_cfg_t *cfg)
+{
+ policy_sa_t *policy;
+
+ if (dir == POLICY_FWD)
+ {
+ policy_sa_fwd_t *fwd;
+ INIT(fwd,
+ .src_ts = src_ts->clone(src_ts),
+ .dst_ts = dst_ts->clone(dst_ts),
+ );
+ policy = &fwd->generic;
+ }
+ else
+ {
+ INIT(policy, .priority = 0);
+ }
+ policy->type = type;
+ policy->sa = ipsec_sa_create(this, src, dst, cfg);
+ return policy;
+}
+
+/**
+ * Destroy a policy_sa(_fwd)_t object
+ */
+static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
+ private_kernel_pfkey_ipsec_t *this)
+{
+ if (*dir == POLICY_FWD)
+ {
+ policy_sa_fwd_t *fwd = (policy_sa_fwd_t*)policy;
+ fwd->src_ts->destroy(fwd->src_ts);
+ fwd->dst_ts->destroy(fwd->dst_ts);
+ }
+ ipsec_sa_destroy(this, policy->sa);
+ free(policy);
+}
+
typedef struct policy_entry_t policy_entry_t;
/**
* installed kernel policy.
*/
struct policy_entry_t {
-
- /** reqid of this policy */
- u_int32_t reqid;
-
- /** index assigned by the kernel */
+ /** Index assigned by the kernel */
u_int32_t index;
- /** direction of this policy: in, out, forward */
+ /** Direction of this policy: in, out, forward */
u_int8_t direction;
- /** parameters of installed policy */
+ /** Parameters of installed policy */
struct {
- /** subnet and port */
+ /** Subnet and port */
host_t *net;
- /** subnet mask */
+ /** Subnet mask */
u_int8_t mask;
- /** protocol */
+ /** Protocol */
u_int8_t proto;
} src, dst;
- /** associated route installed for this policy */
+ /** Associated route installed for this policy */
route_entry_t *route;
- /** by how many CHILD_SA's this policy is used */
- u_int refcount;
+ /** List of SAs this policy is used by, ordered by priority */
+ linked_list_t *used_by;
};
/**
- * create a policy_entry_t object
+ * Create a policy_entry_t object
*/
static policy_entry_t *create_policy_entry(traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t dir, u_int32_t reqid)
+ traffic_selector_t *dst_ts,
+ policy_dir_t dir)
{
- policy_entry_t *policy = malloc_thing(policy_entry_t);
- policy->reqid = reqid;
- policy->index = 0;
- policy->direction = dir;
- policy->route = NULL;
- policy->refcount = 0;
+ policy_entry_t *policy;
+ INIT(policy,
+ .direction = dir,
+ );
src_ts->to_subnet(src_ts, &policy->src.net, &policy->src.mask);
dst_ts->to_subnet(dst_ts, &policy->dst.net, &policy->dst.mask);
/* src or dest proto may be "any" (0), use more restrictive one */
- policy->src.proto = max(src_ts->get_protocol(src_ts), dst_ts->get_protocol(dst_ts));
+ policy->src.proto = max(src_ts->get_protocol(src_ts),
+ dst_ts->get_protocol(dst_ts));
policy->src.proto = policy->src.proto ? policy->src.proto : IPSEC_PROTO_ANY;
policy->dst.proto = policy->src.proto;
@@ -285,23 +455,32 @@ static policy_entry_t *create_policy_entry(traffic_selector_t *src_ts,
}
/**
- * destroy a policy_entry_t object
+ * Destroy a policy_entry_t object
*/
-static void policy_entry_destroy(policy_entry_t *this)
+static void policy_entry_destroy(policy_entry_t *policy,
+ private_kernel_pfkey_ipsec_t *this)
{
- DESTROY_IF(this->src.net);
- DESTROY_IF(this->dst.net);
- if (this->route)
+ if (policy->route)
{
- route_entry_destroy(this->route);
+ route_entry_destroy(policy->route);
}
- free(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->destroy(policy->used_by);
+ }
+ DESTROY_IF(policy->src.net);
+ DESTROY_IF(policy->dst.net);
+ free(policy);
}
/**
* compares two policy_entry_t
*/
-static inline bool policy_entry_equals(policy_entry_t *current, policy_entry_t *policy)
+static inline bool policy_entry_equals(policy_entry_t *current,
+ policy_entry_t *policy)
{
return current->direction == policy->direction &&
current->src.proto == policy->src.proto &&
@@ -315,11 +494,41 @@ static inline bool policy_entry_equals(policy_entry_t *current, policy_entry_t *
/**
* compare the given kernel index with that of a policy
*/
-static inline bool policy_entry_match_byindex(policy_entry_t *current, u_int32_t *index)
+static inline bool policy_entry_match_byindex(policy_entry_t *current,
+ u_int32_t *index)
{
return current->index == *index;
}
+/**
+ * Calculate the priority of a policy
+ */
+static inline u_int32_t get_priority(policy_entry_t *policy,
+ policy_priority_t prio)
+{
+ u_int32_t priority = PRIO_BASE;
+ switch (prio)
+ {
+ case POLICY_PRIORITY_FALLBACK:
+ priority <<= 1;
+ /* fall-through */
+ case POLICY_PRIORITY_ROUTED:
+ priority <<= 1;
+ /* fall-through */
+ case POLICY_PRIORITY_DEFAULT:
+ break;
+ }
+ /* calculate priority based on selector size, small size = high prio */
+ priority -= policy->src.mask;
+ priority -= policy->dst.mask;
+ priority <<= 2; /* make some room for the two flags */
+ priority += policy->src.net->get_port(policy->src.net) ||
+ policy->dst.net->get_port(policy->dst.net) ?
+ 0 : 2;
+ priority += policy->src.proto != IPSEC_PROTO_ANY ? 0 : 1;
+ return priority;
+}
+
typedef struct pfkey_msg_t pfkey_msg_t;
struct pfkey_msg_t
@@ -470,6 +679,23 @@ static u_int8_t dir2kernel(policy_dir_t dir)
}
}
+/**
+ * convert the policy type to the one defined in ipsec.h
+ */
+static inline u_int16_t type2kernel(policy_type_t type)
+{
+ switch (type)
+ {
+ case POLICY_IPSEC:
+ return IPSEC_POLICY_IPSEC;
+ case POLICY_PASS:
+ return IPSEC_POLICY_NONE;
+ case POLICY_DROP:
+ return IPSEC_POLICY_DISCARD;
+ }
+ return type;
+}
+
#ifdef SADB_X_MIGRATE
/**
* convert the policy direction in ipsec.h to the general one.
@@ -665,19 +891,19 @@ static void add_encap_ext(struct sadb_msg *msg, host_t *src, host_t *dst)
nat_type = (struct sadb_x_nat_t_type*)PFKEY_EXT_ADD_NEXT(msg);
nat_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
- nat_type->sadb_x_nat_t_type_len = PFKEY_LEN(sizeof(struct sadb_x_nat_t_type));
+ nat_type->sadb_x_nat_t_type_len = PFKEY_LEN(sizeof(*nat_type));
nat_type->sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP;
PFKEY_EXT_ADD(msg, nat_type);
nat_port = (struct sadb_x_nat_t_port*)PFKEY_EXT_ADD_NEXT(msg);
nat_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
- nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(struct sadb_x_nat_t_port));
+ nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(*nat_port));
nat_port->sadb_x_nat_t_port_port = htons(src->get_port(src));
PFKEY_EXT_ADD(msg, nat_port);
nat_port = (struct sadb_x_nat_t_port*)PFKEY_EXT_ADD_NEXT(msg);
nat_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
- nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(struct sadb_x_nat_t_port));
+ nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(*nat_port));
nat_port->sadb_x_nat_t_port_port = htons(dst->get_port(dst));
PFKEY_EXT_ADD(msg, nat_port);
}
@@ -694,9 +920,11 @@ static traffic_selector_t* sadb_address2ts(struct sadb_address *address)
/* The Linux 2.6 kernel does not set the protocol and port information
* in the src and dst sadb_address extensions of the SADB_ACQUIRE message.
*/
- host = host_create_from_sockaddr((sockaddr_t*)&address[1]) ;
- ts = traffic_selector_create_from_subnet(host, address->sadb_address_prefixlen,
- address->sadb_address_proto, host->get_port(host));
+ host = host_create_from_sockaddr((sockaddr_t*)&address[1]);
+ ts = traffic_selector_create_from_subnet(host,
+ address->sadb_address_prefixlen,
+ address->sadb_address_proto,
+ host->get_port(host));
return ts;
}
@@ -729,7 +957,8 @@ static status_t parse_pfkey_message(struct sadb_msg *msg, pfkey_msg_t *out)
if ((ext->sadb_ext_type > SADB_EXT_MAX) || (!ext->sadb_ext_type))
{
- DBG1(DBG_KNL, "type of PF_KEY extension (%d) is invalid", ext->sadb_ext_type);
+ DBG1(DBG_KNL, "type of PF_KEY extension (%d) is invalid",
+ ext->sadb_ext_type);
break;
}
@@ -784,7 +1013,8 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket
continue;
}
this->mutex_pfkey->unlock(this->mutex_pfkey);
- DBG1(DBG_KNL, "error sending to PF_KEY socket: %s", strerror(errno));
+ DBG1(DBG_KNL, "error sending to PF_KEY socket: %s",
+ strerror(errno));
return FAILED;
}
break;
@@ -804,7 +1034,8 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket
/* interrupted, try again */
continue;
}
- DBG1(DBG_KNL, "error reading from PF_KEY socket: %s", strerror(errno));
+ DBG1(DBG_KNL, "error reading from PF_KEY socket: %s",
+ strerror(errno));
this->mutex_pfkey->unlock(this->mutex_pfkey);
return FAILED;
}
@@ -817,7 +1048,8 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket
}
if (msg->sadb_msg_len > len / PFKEY_ALIGNMENT)
{
- DBG1(DBG_KNL, "buffer was too small to receive the complete PF_KEY message");
+ DBG1(DBG_KNL, "buffer was too small to receive the complete PF_KEY "
+ "message");
this->mutex_pfkey->unlock(this->mutex_pfkey);
return FAILED;
}
@@ -829,7 +1061,8 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket
if (msg->sadb_msg_seq != this->seq)
{
DBG1(DBG_KNL, "received PF_KEY message with unexpected sequence "
- "number, was %d expected %d", msg->sadb_msg_seq, this->seq);
+ "number, was %d expected %d", msg->sadb_msg_seq,
+ this->seq);
if (msg->sadb_msg_seq == 0)
{
/* FreeBSD and Mac OS X do this for the response to
@@ -849,8 +1082,8 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket
if (msg->sadb_msg_type != in->sadb_msg_type)
{
DBG2(DBG_KNL, "received PF_KEY message of wrong type, "
- "was %d expected %d, ignoring",
- msg->sadb_msg_type, in->sadb_msg_type);
+ "was %d expected %d, ignoring", msg->sadb_msg_type,
+ in->sadb_msg_type);
}
break;
}
@@ -860,7 +1093,6 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket
memcpy(*out, buf, len);
this->mutex_pfkey->unlock(this->mutex_pfkey);
-
return SUCCESS;
}
@@ -868,7 +1100,8 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket
* Send a message to the default PF_KEY socket and handle the response.
*/
static status_t pfkey_send(private_kernel_pfkey_ipsec_t *this,
- struct sadb_msg *in, struct sadb_msg **out, size_t *out_len)
+ struct sadb_msg *in, struct sadb_msg **out,
+ size_t *out_len)
{
return pfkey_send_socket(this, this->socket, in, out, out_len);
}
@@ -876,12 +1109,14 @@ static status_t pfkey_send(private_kernel_pfkey_ipsec_t *this,
/**
* Process a SADB_ACQUIRE message from the kernel
*/
-static void process_acquire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg)
+static void process_acquire(private_kernel_pfkey_ipsec_t *this,
+ struct sadb_msg* msg)
{
pfkey_msg_t response;
u_int32_t index, reqid = 0;
traffic_selector_t *src_ts, *dst_ts;
policy_entry_t *policy;
+ policy_sa_t *sa;
switch (msg->sadb_msg_satype)
{
@@ -904,18 +1139,21 @@ static void process_acquire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
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)
+ (linked_list_match_t)policy_entry_match_byindex,
+ (void**)&policy, &index) == SUCCESS &&
+ policy->used_by->get_first(policy->used_by, (void**)&sa) == SUCCESS)
{
- reqid = policy->reqid;
+ reqid = sa->sa->cfg.reqid;
}
else
{
- DBG1(DBG_KNL, "received an SADB_ACQUIRE with policy id %d but no"
- " matching policy found", index);
+ DBG1(DBG_KNL, "received an SADB_ACQUIRE with policy id %d but no "
+ "matching policy found", index);
}
+ this->mutex->unlock(this->mutex);
+
src_ts = sadb_address2ts(response.src);
dst_ts = sadb_address2ts(response.dst);
- this->mutex->unlock(this->mutex);
hydra->kernel_interface->acquire(hydra->kernel_interface, reqid, src_ts,
dst_ts);
@@ -924,7 +1162,8 @@ static void process_acquire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
/**
* Process a SADB_EXPIRE message from the kernel
*/
-static void process_expire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg)
+static void process_expire(private_kernel_pfkey_ipsec_t *this,
+ struct sadb_msg* msg)
{
pfkey_msg_t response;
u_int8_t protocol;
@@ -946,8 +1185,8 @@ static void process_expire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
if (protocol != IPPROTO_ESP && protocol != IPPROTO_AH)
{
- DBG2(DBG_KNL, "ignoring SADB_EXPIRE for SA with SPI %.8x and reqid {%u} "
- "which is not a CHILD_SA", ntohl(spi), reqid);
+ DBG2(DBG_KNL, "ignoring SADB_EXPIRE for SA with SPI %.8x and "
+ "reqid {%u} which is not a CHILD_SA", ntohl(spi), reqid);
return;
}
@@ -959,7 +1198,8 @@ static void process_expire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
/**
* Process a SADB_X_MIGRATE message from the kernel
*/
-static void process_migrate(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg)
+static void process_migrate(private_kernel_pfkey_ipsec_t *this,
+ struct sadb_msg* msg)
{
pfkey_msg_t response;
traffic_selector_t *src_ts, *dst_ts;
@@ -1014,10 +1254,12 @@ static void process_migrate(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
/**
* Process a SADB_X_NAT_T_NEW_MAPPING message from the kernel
*/
-static void process_mapping(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg)
+static void process_mapping(private_kernel_pfkey_ipsec_t *this,
+ struct sadb_msg* msg)
{
pfkey_msg_t response;
u_int32_t spi, reqid;
+ sockaddr_t *sa;
host_t *host;
DBG2(DBG_KNL, "received an SADB_X_NAT_T_NEW_MAPPING");
@@ -1038,30 +1280,33 @@ static void process_mapping(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
spi = response.sa->sadb_sa_spi;
reqid = response.x_sa2->sadb_x_sa2_reqid;
- if (satype2proto(msg->sadb_msg_satype) == IPPROTO_ESP)
+ if (satype2proto(msg->sadb_msg_satype) != IPPROTO_ESP)
+ {
+ return;
+ }
+
+ sa = (sockaddr_t*)(response.dst + 1);
+ switch (sa->sa_family)
{
- sockaddr_t *sa = (sockaddr_t*)(response.dst + 1);
- switch (sa->sa_family)
+ case AF_INET:
{
- case AF_INET:
- {
- struct sockaddr_in *sin = (struct sockaddr_in*)sa;
- sin->sin_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port);
- }
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
- sin6->sin6_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port);
- }
- default:
- break;
+ struct sockaddr_in *sin = (struct sockaddr_in*)sa;
+ sin->sin_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port);
}
- host = host_create_from_sockaddr(sa);
- if (host)
+ case AF_INET6:
{
- hydra->kernel_interface->mapping(hydra->kernel_interface, reqid,
- spi, host);
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
+ sin6->sin6_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port);
}
+ default:
+ break;
+ }
+
+ host = host_create_from_sockaddr(sa);
+ if (host)
+ {
+ hydra->kernel_interface->mapping(hydra->kernel_interface, reqid,
+ spi, host);
}
}
#endif /*SADB_X_NAT_T_NEW_MAPPING*/
@@ -1073,8 +1318,8 @@ static job_requeue_t receive_events(private_kernel_pfkey_ipsec_t *this)
{
unsigned char buf[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg = (struct sadb_msg*)buf;
- int len;
bool oldstate;
+ int len;
oldstate = thread_cancelability(TRUE);
len = recvfrom(this->socket_events, buf, sizeof(buf), 0, NULL, 0);
@@ -1109,7 +1354,8 @@ static job_requeue_t receive_events(private_kernel_pfkey_ipsec_t *this)
}
if (msg->sadb_msg_len > len / PFKEY_ALIGNMENT)
{
- DBG1(DBG_KNL, "buffer was too small to receive the complete PF_KEY message");
+ DBG1(DBG_KNL, "buffer was too small to receive the complete "
+ "PF_KEY message");
return JOB_REQUEUE_DIRECT;
}
@@ -1179,7 +1425,7 @@ METHOD(kernel_ipsec_t, get_spi, status_t,
if (out->sadb_msg_errno)
{
DBG1(DBG_KNL, "allocating SPI failed: %s (%d)",
- strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+ strerror(out->sadb_msg_errno), out->sadb_msg_errno);
}
else if (parse_pfkey_message(out, &response) == SUCCESS)
{
@@ -1222,7 +1468,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
memset(&request, 0, sizeof(request));
- DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", ntohl(spi), reqid);
+ DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
+ ntohl(spi), reqid);
msg = (struct sadb_msg*)request;
msg->sadb_msg_version = PF_KEY_V2;
@@ -1287,11 +1534,11 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
if (!sa->sadb_sa_encrypt)
{
DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
- encryption_algorithm_names, enc_alg);
+ encryption_algorithm_names, enc_alg);
return FAILED;
}
DBG2(DBG_KNL, " using encryption algorithm %N with key size %d",
- encryption_algorithm_names, enc_alg, enc_key.len * 8);
+ encryption_algorithm_names, enc_alg, enc_key.len * 8);
key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
@@ -1307,11 +1554,11 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
if (!sa->sadb_sa_auth)
{
DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
- integrity_algorithm_names, int_alg);
+ integrity_algorithm_names, int_alg);
return FAILED;
}
DBG2(DBG_KNL, " using integrity algorithm %N with key size %d",
- integrity_algorithm_names, int_alg, int_key.len * 8);
+ integrity_algorithm_names, int_alg, int_key.len * 8);
key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
@@ -1368,8 +1615,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
if (!src->ip_equals(src, new_src) ||
!dst->ip_equals(dst, new_dst))
{
- DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: address changes"
- " are not supported", ntohl(spi));
+ DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: address "
+ "changes are not supported", ntohl(spi));
return NOT_SUPPORTED;
}
@@ -1396,27 +1643,27 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
if (pfkey_send(this, msg, &out, &len) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x",
- ntohl(spi));
+ DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi));
return FAILED;
}
else if (out->sadb_msg_errno)
{
DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)",
- ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+ ntohl(spi), strerror(out->sadb_msg_errno),
+ out->sadb_msg_errno);
free(out);
return FAILED;
}
else if (parse_pfkey_message(out, &response) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: parsing response "
- "from kernel failed", ntohl(spi));
+ DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: parsing "
+ "response from kernel failed", ntohl(spi));
free(out);
return FAILED;
}
DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
- ntohl(spi), src, dst, new_src, new_dst);
+ ntohl(spi), src, dst, new_src, new_dst);
memset(&request, 0, sizeof(request));
@@ -1476,7 +1723,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
else if (out->sadb_msg_errno)
{
DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: %s (%d)",
- ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+ ntohl(spi), strerror(out->sadb_msg_errno),
+ out->sadb_msg_errno);
free(out);
return FAILED;
}
@@ -1525,7 +1773,8 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
else if (out->sadb_msg_errno)
{
DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)",
- ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+ ntohl(spi), strerror(out->sadb_msg_errno),
+ out->sadb_msg_errno);
free(out);
return FAILED;
}
@@ -1580,7 +1829,8 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
else if (out->sadb_msg_errno)
{
DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x: %s (%d)",
- ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+ ntohl(spi), strerror(out->sadb_msg_errno),
+ out->sadb_msg_errno);
free(out);
return FAILED;
}
@@ -1590,57 +1840,60 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
return SUCCESS;
}
-METHOD(kernel_ipsec_t, add_policy, status_t,
- private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
- traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
- policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
- mark_t mark, bool routed)
+METHOD(kernel_ipsec_t, flush_sas, status_t,
+ private_kernel_pfkey_ipsec_t *this)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
- struct sadb_x_policy *pol;
- struct sadb_x_ipsecrequest *req;
- policy_entry_t *policy, *found = NULL;
- pfkey_msg_t response;
size_t len;
- if (dir2kernel(direction) == IPSEC_DIR_INVALID)
- {
- /* FWD policies are not supported on all platforms */
- return SUCCESS;
- }
+ memset(&request, 0, sizeof(request));
- /* create a policy */
- policy = create_policy_entry(src_ts, dst_ts, direction, sa->reqid);
+ DBG2(DBG_KNL, "flushing all SAD entries");
- /* 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)
+ msg = (struct sadb_msg*)request;
+ msg->sadb_msg_version = PF_KEY_V2;
+ msg->sadb_msg_type = SADB_FLUSH;
+ msg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
+ msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
+
+ if (pfkey_send(this, msg, &out, &len) != SUCCESS)
{
- /* use existing policy */
- found->refcount++;
- DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
- "refcount", src_ts, dst_ts,
- policy_dir_names, direction);
- policy_entry_destroy(policy);
- policy = found;
+ DBG1(DBG_KNL, "unable to flush SAD entries");
+ return FAILED;
}
- else
+ else if (out->sadb_msg_errno)
{
- /* apply the new one, if we have no such policy */
- this->policies->insert_last(this->policies, policy);
- policy->refcount = 1;
+ DBG1(DBG_KNL, "unable to flush SAD entries: %s (%d)",
+ strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+ free(out);
+ return FAILED;
}
+ free(out);
+ return SUCCESS;
+}
- memset(&request, 0, sizeof(request));
+/**
+ * Add or update a policy in the kernel.
+ *
+ * Note: The mutex has to be locked when entering this function.
+ */
+static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
+ policy_entry_t *policy, policy_sa_t *mapping, bool update)
+{
+ unsigned char request[PFKEY_BUFFER_SIZE];
+ struct sadb_msg *msg, *out;
+ struct sadb_x_policy *pol;
+ struct sadb_x_ipsecrequest *req;
+ ipsec_sa_t *ipsec = mapping->sa;
+ pfkey_msg_t response;
+ size_t len;
- DBG2(DBG_KNL, "adding policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
+ memset(&request, 0, sizeof(request));
msg = (struct sadb_msg*)request;
msg->sadb_msg_version = PF_KEY_V2;
- msg->sadb_msg_type = found ? SADB_X_SPDUPDATE : SADB_X_SPDADD;
+ msg->sadb_msg_type = update ? SADB_X_SPDUPDATE : SADB_X_SPDADD;
msg->sadb_msg_satype = 0;
msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
@@ -1648,32 +1901,27 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy));
pol->sadb_x_policy_id = 0;
- pol->sadb_x_policy_dir = dir2kernel(direction);
- pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+ pol->sadb_x_policy_dir = dir2kernel(policy->direction);
+ pol->sadb_x_policy_type = type2kernel(mapping->type);
#ifdef HAVE_STRUCT_SADB_X_POLICY_SADB_X_POLICY_PRIORITY
- /* calculate priority based on selector size, small size = high prio */
- pol->sadb_x_policy_priority = routed ? PRIO_LOW : PRIO_HIGH;
- pol->sadb_x_policy_priority -= policy->src.mask;
- pol->sadb_x_policy_priority -= policy->dst.mask;
- pol->sadb_x_policy_priority <<= 2; /* make some room for the flags */
- pol->sadb_x_policy_priority += policy->src.net->get_port(policy->src.net) ||
- policy->dst.net->get_port(policy->dst.net) ? 0 : 2;
- pol->sadb_x_policy_priority += policy->src.proto != IPSEC_PROTO_ANY ? 0 : 1;
+ pol->sadb_x_policy_priority = mapping->priority;
#endif
- /* one or more sadb_x_ipsecrequest extensions are added to the sadb_x_policy extension */
+ /* one or more sadb_x_ipsecrequest extensions are added to the
+ * sadb_x_policy extension */
req = (struct sadb_x_ipsecrequest*)(pol + 1);
- req->sadb_x_ipsecrequest_proto = sa->esp.use ? IPPROTO_ESP : IPPROTO_AH;
- /* !!! the length of this struct MUST be in octets instead of 64 bit words */
+ req->sadb_x_ipsecrequest_proto = ipsec->cfg.esp.use ? IPPROTO_ESP
+ : IPPROTO_AH;
+ /* !!! the length here MUST be in octets instead of 64 bit words */
req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest);
- req->sadb_x_ipsecrequest_mode = mode2kernel(sa->mode);
- req->sadb_x_ipsecrequest_reqid = sa->reqid;
+ req->sadb_x_ipsecrequest_mode = mode2kernel(ipsec->cfg.mode);
+ req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid;
req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE;
- if (sa->mode == MODE_TUNNEL)
+ if (ipsec->cfg.mode == MODE_TUNNEL)
{
- len = hostcpy(req + 1, src);
+ len = hostcpy(req + 1, ipsec->src);
req->sadb_x_ipsecrequest_len += len;
- len = hostcpy((char*)(req + 1) + len, dst);
+ len = hostcpy((char*)(req + 1) + len, ipsec->dst);
req->sadb_x_ipsecrequest_len += len;
}
@@ -1701,33 +1949,31 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
if (pfkey_send(this, msg, &out, &len) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to add policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
return FAILED;
}
else if (out->sadb_msg_errno)
{
- DBG1(DBG_KNL, "unable to add policy %R === %R %N: %s (%d)", src_ts, dst_ts,
- policy_dir_names, direction,
- strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+ DBG1(DBG_KNL, "unable to %s policy: %s (%d)",
+ update ? "update" : "add", strerror(out->sadb_msg_errno),
+ out->sadb_msg_errno);
free(out);
return FAILED;
}
else if (parse_pfkey_message(out, &response) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to add policy %R === %R %N: parsing response "
- "from kernel failed", src_ts, dst_ts, policy_dir_names, direction);
+ DBG1(DBG_KNL, "unable to %s policy: parsing response from kernel "
+ "failed", update ? "update" : "add");
free(out);
return FAILED;
}
- this->mutex->lock(this->mutex);
-
/* we try to find the policy again and update the kernel index */
- if (this->policies->find_last(this->policies, NULL, (void**)&policy) != SUCCESS)
+ this->mutex->lock(this->mutex);
+ if (this->policies->find_last(this->policies, NULL,
+ (void**)&policy) != SUCCESS)
{
- DBG2(DBG_KNL, "unable to update index, the policy %R === %R %N is "
- "already gone, ignoring", src_ts, dst_ts, policy_dir_names, direction);
+ DBG2(DBG_KNL, "unable to update index, the policy is already gone, "
+ "ignoring");
this->mutex->unlock(this->mutex);
free(out);
return SUCCESS;
@@ -1736,53 +1982,83 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
free(out);
/* install a route, if:
- * - we are NOT updating a policy
* - this is a forward policy (to just get one for each child)
* - we are in tunnel mode
- * - we are not using IPv6 (does not work correctly yet!)
* - routing is not disabled via strongswan.conf
*/
- if (policy->route == NULL && direction == POLICY_FWD &&
- sa->mode != MODE_TRANSPORT && src->get_family(src) != AF_INET6 &&
- this->install_routes)
+ if (policy->direction == POLICY_FWD &&
+ ipsec->cfg.mode != MODE_TRANSPORT && this->install_routes)
{
route_entry_t *route = malloc_thing(route_entry_t);
+ policy_sa_fwd_t *fwd = (policy_sa_fwd_t*)mapping;
if (hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface,
- dst_ts, &route->src_ip) == SUCCESS)
+ fwd->dst_ts, &route->src_ip) == SUCCESS)
{
/* get the nexthop to src (src as we are in POLICY_FWD).*/
route->gateway = hydra->kernel_interface->get_nexthop(
- hydra->kernel_interface, src);
+ hydra->kernel_interface, ipsec->src);
+ /* install route via outgoing interface */
route->if_name = hydra->kernel_interface->get_interface(
- hydra->kernel_interface, dst);
- route->dst_net = chunk_clone(policy->src.net->get_address(policy->src.net));
+ hydra->kernel_interface, ipsec->dst);
+ route->dst_net = chunk_clone(policy->src.net->get_address(
+ policy->src.net));
route->prefixlen = policy->src.mask;
- if (route->if_name)
+ if (!route->if_name)
{
- switch (hydra->kernel_interface->add_route(
- hydra->kernel_interface, route->dst_net,
- route->prefixlen, route->gateway,
- route->src_ip, route->if_name))
+ this->mutex->unlock(this->mutex);
+ route_entry_destroy(route);
+ return SUCCESS;
+ }
+
+ if (policy->route)
+ {
+ route_entry_t *old = policy->route;
+ if (route_entry_equals(old, route))
+ { /* keep previously installed route. since it might have
+ * still been removed by an address change, we install it
+ * again but ignore the result */
+ hydra->kernel_interface->add_route(hydra->kernel_interface,
+ route->dst_net, route->prefixlen, route->gateway,
+ route->src_ip, route->if_name);
+ this->mutex->unlock(this->mutex);
+ route_entry_destroy(route);
+ return SUCCESS;
+ }
+ /* uninstall previously installed route */
+ if (hydra->kernel_interface->del_route(hydra->kernel_interface,
+ old->dst_net, old->prefixlen, old->gateway,
+ old->src_ip, old->if_name) != SUCCESS)
{
- default:
- DBG1(DBG_KNL, "unable to install source route for %H",
- route->src_ip);
- /* FALL */
- case ALREADY_DONE:
- /* route exists, do not uninstall */
- route_entry_destroy(route);
- break;
- case SUCCESS:
- /* cache the installed route */
- policy->route = route;
- break;
+ DBG1(DBG_KNL, "error uninstalling route installed with "
+ "policy %R === %R %N", fwd->src_ts,
+ fwd->dst_ts, policy_dir_names,
+ policy->direction);
}
+ route_entry_destroy(old);
+ policy->route = NULL;
}
- else
+
+ DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s",
+ fwd->src_ts, route->gateway, route->src_ip, route->if_name);
+ switch (hydra->kernel_interface->add_route(
+ hydra->kernel_interface, route->dst_net,
+ route->prefixlen, route->gateway,
+ route->src_ip, route->if_name))
{
- route_entry_destroy(route);
+ default:
+ DBG1(DBG_KNL, "unable to install source route for %H",
+ route->src_ip);
+ /* FALL */
+ case ALREADY_DONE:
+ /* route exists, do not uninstall */
+ route_entry_destroy(route);
+ break;
+ case SUCCESS:
+ /* cache the installed route */
+ policy->route = route;
+ break;
}
}
else
@@ -1790,9 +2066,82 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
free(route);
}
}
-
this->mutex->unlock(this->mutex);
+ return SUCCESS;
+}
+
+METHOD(kernel_ipsec_t, add_policy, status_t,
+ private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
+ policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
+ mark_t mark, policy_priority_t priority)
+{
+ policy_entry_t *policy, *found = NULL;
+ policy_sa_t *assigned_sa, *current_sa;
+ enumerator_t *enumerator;
+ bool update = TRUE;
+
+ if (dir2kernel(direction) == IPSEC_DIR_INVALID)
+ { /* FWD policies are not supported on all platforms */
+ return SUCCESS;
+ }
+
+ /* create a policy */
+ policy = create_policy_entry(src_ts, dst_ts, direction);
+
+ /* 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)
+ { /* use existing policy */
+ DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
+ "refcount", src_ts, dst_ts, policy_dir_names, direction);
+ policy_entry_destroy(policy, this);
+ policy = found;
+ }
+ else
+ { /* use the new one, if we have no such policy */
+ this->policies->insert_last(this->policies, policy);
+ policy->used_by = linked_list_create();
+ }
+ /* cache the assigned IPsec SA */
+ assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts,
+ dst_ts, sa);
+ assigned_sa->priority = get_priority(policy, priority);
+
+ /* insert the SA according to its priority */
+ enumerator = policy->used_by->create_enumerator(policy->used_by);
+ while (enumerator->enumerate(enumerator, (void**)&current_sa))
+ {
+ if (current_sa->priority >= assigned_sa->priority)
+ {
+ break;
+ }
+ update = FALSE;
+ }
+ policy->used_by->insert_before(policy->used_by, enumerator, assigned_sa);
+ enumerator->destroy(enumerator);
+
+ if (!update)
+ { /* we don't update the policy if the priority is lower than that of the
+ * currently installed one */
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+ }
+
+ DBG2(DBG_KNL, "%s policy %R === %R %N",
+ found ? "updating" : "adding", src_ts, dst_ts,
+ policy_dir_names, direction);
+
+ if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unable to %s policy %R === %R %N",
+ found ? "update" : "add", src_ts, dst_ts,
+ policy_dir_names, direction);
+ return FAILED;
+ }
return SUCCESS;
}
@@ -1809,8 +2158,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
size_t len;
if (dir2kernel(direction) == IPSEC_DIR_INVALID)
- {
- /* FWD policies are not supported on all platforms */
+ { /* FWD policies are not supported on all platforms */
return NOT_FOUND;
}
@@ -1818,20 +2166,21 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
policy_dir_names, direction);
/* create a policy */
- policy = create_policy_entry(src_ts, dst_ts, direction, 0);
+ policy = create_policy_entry(src_ts, dst_ts, direction);
/* 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)
+ (linked_list_match_t)policy_entry_equals,
+ (void**)&found, policy) != SUCCESS)
{
DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found", src_ts,
dst_ts, policy_dir_names, direction);
- policy_entry_destroy(policy);
+ policy_entry_destroy(policy, this);
this->mutex->unlock(this->mutex);
return NOT_FOUND;
}
- policy_entry_destroy(policy);
+ policy_entry_destroy(policy, this);
policy = found;
memset(&request, 0, sizeof(request));
@@ -1874,17 +2223,19 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
else if (parse_pfkey_message(out, &response) != SUCCESS)
{
DBG1(DBG_KNL, "unable to query policy %R === %R %N: parsing response "
- "from kernel failed", src_ts, dst_ts, policy_dir_names, direction);
+ "from kernel failed", src_ts, dst_ts, policy_dir_names,
+ direction);
free(out);
return FAILED;
}
else if (response.lft_current == NULL)
{
DBG1(DBG_KNL, "unable to query policy %R === %R %N: kernel reports no "
- "use time", src_ts, dst_ts, policy_dir_names, direction);
+ "use time", src_ts, dst_ts, policy_dir_names, direction);
free(out);
return FAILED;
}
+
/* we need the monotonic time, but the kernel returns system time. */
if (response.lft_current->sadb_lifetime_usetime)
{
@@ -1896,25 +2247,26 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
*use_time = 0;
}
free(out);
-
return SUCCESS;
}
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
- bool unrouted)
+ traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ mark_t mark, policy_priority_t prio)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
struct sadb_x_policy *pol;
policy_entry_t *policy, *found = NULL;
- route_entry_t *route;
+ policy_sa_t *mapping;
+ enumerator_t *enumerator;
+ bool is_installed = TRUE;
+ u_int32_t priority;
size_t len;
if (dir2kernel(direction) == IPSEC_DIR_INVALID)
- {
- /* FWD policies are not supported on all platforms */
+ { /* FWD policies are not supported on all platforms */
return SUCCESS;
}
@@ -1922,35 +2274,59 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
policy_dir_names, direction);
/* create a policy */
- policy = create_policy_entry(src_ts, dst_ts, direction, 0);
+ policy = create_policy_entry(src_ts, dst_ts, direction);
/* 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 (--found->refcount > 0)
- {
- /* is used by more SAs, keep in kernel */
- DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
- policy_entry_destroy(policy);
- this->mutex->unlock(this->mutex);
- return SUCCESS;
- }
- /* remove if last reference */
- this->policies->remove(this->policies, found, NULL);
- policy_entry_destroy(policy);
- policy = found;
- }
- else
+ (linked_list_match_t)policy_entry_equals,
+ (void**)&found, policy) != SUCCESS)
{
DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts,
dst_ts, policy_dir_names, direction);
- policy_entry_destroy(policy);
+ policy_entry_destroy(policy, this);
this->mutex->unlock(this->mutex);
return NOT_FOUND;
}
- this->mutex->unlock(this->mutex);
+ policy_entry_destroy(policy, this);
+ policy = found;
+
+ /* remove mapping to SA by reqid and priority */
+ priority = get_priority(policy, prio);
+ enumerator = policy->used_by->create_enumerator(policy->used_by);
+ while (enumerator->enumerate(enumerator, (void**)&mapping))
+ {
+ if (reqid == mapping->sa->cfg.reqid && priority == mapping->priority)
+ {
+ policy->used_by->remove_at(policy->used_by, enumerator);
+ break;
+ }
+ is_installed = FALSE;
+ }
+ enumerator->destroy(enumerator);
+
+ 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, &direction, this);
+
+ if (!is_installed)
+ { /* no need to update as the policy was not installed for this SA */
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+ }
+
+ DBG2(DBG_KNL, "updating policy %R === %R %N", src_ts, dst_ts,
+ policy_dir_names, direction);
+ policy->used_by->get_first(policy->used_by, (void**)&mapping);
+ if (add_policy_internal(this, policy, mapping, TRUE) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unable to update policy %R === %R %N",
+ src_ts, dst_ts, policy_dir_names, direction);
+ return FAILED;
+ }
+ return SUCCESS;
+ }
memset(&request, 0, sizeof(request));
@@ -1964,7 +2340,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy));
pol->sadb_x_policy_dir = dir2kernel(direction);
- pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+ pol->sadb_x_policy_type = type2kernel(mapping->type);
PFKEY_EXT_ADD(msg, pol);
add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto,
@@ -1972,9 +2348,23 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto,
policy->dst.mask);
- route = policy->route;
- policy->route = NULL;
- policy_entry_destroy(policy);
+ if (policy->route)
+ {
+ route_entry_t *route = policy->route;
+ if (hydra->kernel_interface->del_route(hydra->kernel_interface,
+ route->dst_net, route->prefixlen, route->gateway,
+ route->src_ip, route->if_name) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "error uninstalling route installed with "
+ "policy %R === %R %N", src_ts, dst_ts,
+ policy_dir_names, direction);
+ }
+ }
+
+ this->policies->remove(this->policies, found, NULL);
+ policy_sa_destroy(mapping, &direction, this);
+ policy_entry_destroy(policy, this);
+ this->mutex->unlock(this->mutex);
if (pfkey_send(this, msg, &out, &len) != SUCCESS)
{
@@ -1991,25 +2381,44 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
return FAILED;
}
free(out);
+ return SUCCESS;
+}
+
+METHOD(kernel_ipsec_t, flush_policies, status_t,
+ private_kernel_pfkey_ipsec_t *this)
+{
+ unsigned char request[PFKEY_BUFFER_SIZE];
+ struct sadb_msg *msg, *out;
+ size_t len;
+
+ memset(&request, 0, sizeof(request));
+
+ DBG2(DBG_KNL, "flushing all policies from SPD");
- if (route)
+ msg = (struct sadb_msg*)request;
+ msg->sadb_msg_version = PF_KEY_V2;
+ msg->sadb_msg_type = SADB_X_SPDFLUSH;
+ msg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
+ msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
+
+ if (pfkey_send(this, msg, &out, &len) != SUCCESS)
{
- if (hydra->kernel_interface->del_route(hydra->kernel_interface,
- route->dst_net, route->prefixlen, route->gateway,
- route->src_ip, route->if_name) != SUCCESS)
- {
- DBG1(DBG_KNL, "error uninstalling route installed with "
- "policy %R === %R %N", src_ts, dst_ts,
- policy_dir_names, direction);
- }
- route_entry_destroy(route);
+ DBG1(DBG_KNL, "unable to flush SPD entries");
+ return FAILED;
}
-
+ else if (out->sadb_msg_errno)
+ {
+ DBG1(DBG_KNL, "unable to flush SPD entries: %s (%d)",
+ strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+ free(out);
+ return FAILED;
+ }
+ free(out);
return SUCCESS;
}
/**
- * Register a socket for AQUIRE/EXPIRE messages
+ * Register a socket for ACQUIRE/EXPIRE messages
*/
static status_t register_pfkey_socket(private_kernel_pfkey_ipsec_t *this,
u_int8_t satype)
@@ -2075,14 +2484,14 @@ METHOD(kernel_ipsec_t, bypass_socket, bool,
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
- strerror(errno));
+ strerror(errno));
return FALSE;
}
policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
{
DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
- strerror(errno));
+ strerror(errno));
return FALSE;
}
return TRUE;
@@ -2103,7 +2512,11 @@ METHOD(kernel_ipsec_t, destroy, void,
{
close(this->socket_events);
}
- this->policies->destroy_function(this->policies, (void*)policy_entry_destroy);
+ this->policies->invoke_function(this->policies,
+ (linked_list_invoke_t)policy_entry_destroy,
+ this);
+ this->policies->destroy(this->policies);
+ this->sas->destroy(this->sas);
this->mutex->destroy(this->mutex);
this->mutex_pfkey->destroy(this->mutex_pfkey);
free(this);
@@ -2125,14 +2538,18 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
.update_sa = _update_sa,
.query_sa = _query_sa,
.del_sa = _del_sa,
+ .flush_sas = _flush_sas,
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
+ .flush_policies = _flush_policies,
.bypass_socket = _bypass_socket,
.destroy = _destroy,
},
},
.policies = linked_list_create(),
+ .sas = hashtable_create((hashtable_hash_t)ipsec_sa_hash,
+ (hashtable_equals_t)ipsec_sa_equals, 32),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.mutex_pfkey = mutex_create(MUTEX_TYPE_DEFAULT),
.install_routes = lib->settings->get_bool(lib->settings,
@@ -2172,8 +2589,8 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
return NULL;
}
- this->job = callback_job_create((callback_job_cb_t)receive_events,
- this, NULL, NULL);
+ this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
lib->processor->queue_job(lib->processor, (job_t*)this->job);
return &this->public;
diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c
index 842511181..894175402 100644
--- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c
+++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c
@@ -38,11 +38,20 @@ METHOD(plugin_t, get_name, char*,
return "kernel-pfkey";
}
+METHOD(plugin_t, get_features, int,
+ private_kernel_pfkey_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(kernel_ipsec_register, kernel_pfkey_ipsec_create),
+ PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
+ };
+ *features = f;
+ return countof(f);
+}
+
METHOD(plugin_t, destroy, void,
private_kernel_pfkey_plugin_t *this)
{
- hydra->kernel_interface->remove_ipsec_interface(hydra->kernel_interface,
- (kernel_ipsec_constructor_t)kernel_pfkey_ipsec_create);
free(this);
}
@@ -57,13 +66,11 @@ plugin_t *kernel_pfkey_plugin_create()
.public = {
.plugin = {
.get_name = _get_name,
- .reload = (void*)return_false,
+ .get_features = _get_features,
.destroy = _destroy,
},
},
);
- hydra->kernel_interface->add_ipsec_interface(hydra->kernel_interface,
- (kernel_ipsec_constructor_t)kernel_pfkey_ipsec_create);
return &this->public.plugin;
}
diff --git a/src/libhydra/plugins/kernel_pfroute/Makefile.in b/src/libhydra/plugins/kernel_pfroute/Makefile.in
index b7e12561d..1412db0ec 100644
--- a/src/libhydra/plugins/kernel_pfroute/Makefile.in
+++ b/src/libhydra/plugins/kernel_pfroute/Makefile.in
@@ -195,6 +195,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -203,6 +206,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -219,11 +223,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -267,6 +273,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
diff --git a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
index fca46bfd2..5464568df 100644
--- a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
+++ b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
@@ -710,8 +710,8 @@ kernel_pfroute_net_t *kernel_pfroute_net_create()
return NULL;
}
- this->job = callback_job_create((callback_job_cb_t)receive_events,
- this, NULL, NULL);
+ this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
lib->processor->queue_job(lib->processor, (job_t*)this->job);
if (init_address_list(this) != SUCCESS)
diff --git a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_plugin.c b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_plugin.c
index 680caa5d0..09068b33e 100644
--- a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_plugin.c
+++ b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_plugin.c
@@ -38,11 +38,20 @@ METHOD(plugin_t, get_name, char*,
return "kernel-pfroute";
}
+METHOD(plugin_t, get_features, int,
+ private_kernel_pfroute_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(kernel_net_register, kernel_pfroute_net_create),
+ PLUGIN_PROVIDE(CUSTOM, "kernel-net"),
+ };
+ *features = f;
+ return countof(f);
+}
+
METHOD(plugin_t, destroy, void,
private_kernel_pfroute_plugin_t *this)
{
- hydra->kernel_interface->remove_net_interface(hydra->kernel_interface,
- (kernel_net_constructor_t)kernel_pfroute_net_create);
free(this);
}
@@ -57,13 +66,11 @@ plugin_t *kernel_pfroute_plugin_create()
.public = {
.plugin = {
.get_name = _get_name,
- .reload = (void*)return_false,
+ .get_features = _get_features,
.destroy = _destroy,
},
},
);
- hydra->kernel_interface->add_net_interface(hydra->kernel_interface,
- (kernel_net_constructor_t)kernel_pfroute_net_create);
return &this->public.plugin;
}
diff --git a/src/libhydra/plugins/resolve/Makefile.in b/src/libhydra/plugins/resolve/Makefile.in
index d3cda309a..41846ffe0 100644
--- a/src/libhydra/plugins/resolve/Makefile.in
+++ b/src/libhydra/plugins/resolve/Makefile.in
@@ -194,6 +194,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -202,6 +205,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -218,11 +222,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -266,6 +272,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
diff --git a/src/libhydra/plugins/resolve/resolve_handler.c b/src/libhydra/plugins/resolve/resolve_handler.c
index feb2fd05a..011ebbaaf 100644
--- a/src/libhydra/plugins/resolve/resolve_handler.c
+++ b/src/libhydra/plugins/resolve/resolve_handler.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -15,12 +16,20 @@
#include "resolve_handler.h"
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <hydra.h>
#include <debug.h>
#include <threading/mutex.h>
+/* path to resolvconf executable */
+#define RESOLVCONF_EXEC "/sbin/resolvconf"
+
+/* default prefix used for resolvconf interfaces (should have high prio) */
+#define RESOLVCONF_PREFIX "lo.inet.ipsec."
+
typedef struct private_resolve_handler_t private_resolve_handler_t;
/**
@@ -39,49 +48,40 @@ struct private_resolve_handler_t {
char *file;
/**
+ * use resolvconf instead of writing directly to resolv.conf
+ */
+ bool use_resolvconf;
+
+ /**
+ * prefix to be used for interface names sent to resolvconf
+ */
+ char *iface_prefix;
+
+ /**
* Mutex to access file exclusively
*/
mutex_t *mutex;
};
/**
- * Implementation of attribute_handler_t.handle
+ * Writes the given nameserver to resolv.conf
*/
-static bool handle(private_resolve_handler_t *this, identification_t *server,
- configuration_attribute_type_t type, chunk_t data)
+static bool write_nameserver(private_resolve_handler_t *this,
+ identification_t *server, host_t *addr)
{
FILE *in, *out;
char buf[1024];
- host_t *addr;
size_t len;
bool handled = FALSE;
- switch (type)
- {
- case INTERNAL_IP4_DNS:
- addr = host_create_from_chunk(AF_INET, data, 0);
- break;
- case INTERNAL_IP6_DNS:
- addr = host_create_from_chunk(AF_INET6, data, 0);
- break;
- default:
- return FALSE;
- }
-
- if (!addr || addr->is_anyaddr(addr))
- {
- DESTROY_IF(addr);
- return FALSE;
- }
- this->mutex->lock(this->mutex);
-
in = fopen(this->file, "r");
/* allows us to stream from in to out */
unlink(this->file);
out = fopen(this->file, "w");
if (out)
{
- fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr, server);
+ fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr,
+ server);
DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
handled = TRUE;
@@ -99,40 +99,17 @@ static bool handle(private_resolve_handler_t *this, identification_t *server,
{
fclose(in);
}
- this->mutex->unlock(this->mutex);
- addr->destroy(addr);
-
- if (!handled)
- {
- DBG1(DBG_IKE, "adding DNS server failed", this->file);
- }
return handled;
}
/**
- * Implementation of attribute_handler_t.release
+ * Removes the given nameserver from resolv.conf
*/
-static void release(private_resolve_handler_t *this, identification_t *server,
- configuration_attribute_type_t type, chunk_t data)
+static void remove_nameserver(private_resolve_handler_t *this,
+ identification_t *server, host_t *addr)
{
FILE *in, *out;
char line[1024], matcher[512];
- host_t *addr;
- int family;
-
- switch (type)
- {
- case INTERNAL_IP4_DNS:
- family = AF_INET;
- break;
- case INTERNAL_IP6_DNS:
- family = AF_INET6;
- break;
- default:
- return;
- }
-
- this->mutex->lock(this->mutex);
in = fopen(this->file, "r");
if (in)
@@ -142,7 +119,6 @@ static void release(private_resolve_handler_t *this, identification_t *server,
out = fopen(this->file, "w");
if (out)
{
- addr = host_create_from_chunk(family, data, 0);
snprintf(matcher, sizeof(matcher),
"nameserver %H # by strongSwan, from %Y\n",
addr, server);
@@ -160,13 +136,129 @@ static void release(private_resolve_handler_t *this, identification_t *server,
fputs(line, out);
}
}
- addr->destroy(addr);
fclose(out);
}
fclose(in);
}
+}
+/**
+ * Add or remove the given nameserver by invoking resolvconf.
+ */
+static bool invoke_resolvconf(private_resolve_handler_t *this,
+ identification_t *server, host_t *addr,
+ bool install)
+{
+ char cmd[128];
+
+ /* we use the nameserver's IP address as part of the interface name to
+ * make them unique */
+ if (snprintf(cmd, sizeof(cmd), "%s %s %s%H", RESOLVCONF_EXEC,
+ install ? "-a" : "-d", this->iface_prefix, addr) >= sizeof(cmd))
+ {
+ return FALSE;
+ }
+
+ if (install)
+ {
+ FILE *out;
+
+ out = popen(cmd, "w");
+ if (!out)
+ {
+ return FALSE;
+ }
+ DBG1(DBG_IKE, "installing DNS server %H via resolvconf", addr);
+ fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr,
+ server);
+ if (ferror(out) || pclose(out))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ ignore_result(system(cmd));
+ }
+ return TRUE;
+}
+
+METHOD(attribute_handler_t, handle, bool,
+ private_resolve_handler_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ host_t *addr;
+ bool handled;
+
+ switch (type)
+ {
+ case INTERNAL_IP4_DNS:
+ addr = host_create_from_chunk(AF_INET, data, 0);
+ break;
+ case INTERNAL_IP6_DNS:
+ addr = host_create_from_chunk(AF_INET6, data, 0);
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!addr || addr->is_anyaddr(addr))
+ {
+ DESTROY_IF(addr);
+ return FALSE;
+ }
+
+ this->mutex->lock(this->mutex);
+ if (this->use_resolvconf)
+ {
+ handled = invoke_resolvconf(this, server, addr, TRUE);
+ }
+ else
+ {
+ handled = write_nameserver(this, server, addr);
+ }
this->mutex->unlock(this->mutex);
+ addr->destroy(addr);
+
+ if (!handled)
+ {
+ DBG1(DBG_IKE, "adding DNS server failed");
+ }
+ return handled;
+}
+
+METHOD(attribute_handler_t, release, void,
+ private_resolve_handler_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ host_t *addr;
+ int family;
+
+ switch (type)
+ {
+ case INTERNAL_IP4_DNS:
+ family = AF_INET;
+ break;
+ case INTERNAL_IP6_DNS:
+ family = AF_INET6;
+ break;
+ default:
+ return;
+ }
+ addr = host_create_from_chunk(family, data, 0);
+
+ this->mutex->lock(this->mutex);
+ if (this->use_resolvconf)
+ {
+ invoke_resolvconf(this, server, addr, FALSE);
+ }
+ else
+ {
+ remove_nameserver(this, server, addr);
+ }
+ this->mutex->unlock(this->mutex);
+
+ addr->destroy(addr);
}
/**
@@ -179,11 +271,9 @@ typedef struct {
host_t *vip;
} attribute_enumerator_t;
-/**
- * Implementation of create_attribute_enumerator().enumerate()
- */
static bool attribute_enumerate(attribute_enumerator_t *this,
- configuration_attribute_type_t *type, chunk_t *data)
+ configuration_attribute_type_t *type,
+ chunk_t *data)
{
switch (this->vip->get_family(this->vip))
{
@@ -202,11 +292,8 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
return TRUE;
}
-/**
- * Implementation of attribute_handler_t.create_attribute_enumerator
- */
-static enumerator_t* create_attribute_enumerator(private_resolve_handler_t *this,
- identification_t *server, host_t *vip)
+METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
+ private_resolve_handler_t *this, identification_t *server, host_t *vip)
{
if (vip)
{
@@ -222,10 +309,8 @@ static enumerator_t* create_attribute_enumerator(private_resolve_handler_t *this
return enumerator_create_empty();
}
-/**
- * Implementation of resolve_handler_t.destroy.
- */
-static void destroy(private_resolve_handler_t *this)
+METHOD(resolve_handler_t, destroy, void,
+ private_resolve_handler_t *this)
{
this->mutex->destroy(this->mutex);
free(this);
@@ -236,16 +321,30 @@ static void destroy(private_resolve_handler_t *this)
*/
resolve_handler_t *resolve_handler_create()
{
- private_resolve_handler_t *this = malloc_thing(private_resolve_handler_t);
+ private_resolve_handler_t *this;
+ struct stat st;
- this->public.handler.handle = (bool(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))handle;
- this->public.handler.release = (void(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))release;
- this->public.handler.create_attribute_enumerator = (enumerator_t*(*)(attribute_handler_t*, identification_t *server, host_t *vip))create_attribute_enumerator;
- this->public.destroy = (void(*)(resolve_handler_t*))destroy;
+ INIT(this,
+ .public = {
+ .handler = {
+ .handle = _handle,
+ .release = _release,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ },
+ .destroy = _destroy,
+ },
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .file = lib->settings->get_str(lib->settings, "%s.plugins.resolve.file",
+ RESOLV_CONF, hydra->daemon),
+ );
- this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
- this->file = lib->settings->get_str(lib->settings,
- "%s.plugins.resolve.file", RESOLV_CONF, hydra->daemon);
+ if (stat(RESOLVCONF_EXEC, &st) == 0)
+ {
+ this->use_resolvconf = TRUE;
+ this->iface_prefix = lib->settings->get_str(lib->settings,
+ "%s.plugins.resolve.resolvconf.iface_prefix",
+ RESOLVCONF_PREFIX, hydra->daemon);
+ }
return &this->public;
}
diff --git a/src/libhydra/plugins/resolve/resolve_plugin.c b/src/libhydra/plugins/resolve/resolve_plugin.c
index d23d36127..f95827ed9 100644
--- a/src/libhydra/plugins/resolve/resolve_plugin.c
+++ b/src/libhydra/plugins/resolve/resolve_plugin.c
@@ -31,7 +31,7 @@ struct private_resolve_plugin_t {
resolve_plugin_t public;
/**
- * The registerd DNS attribute handler
+ * The registered DNS attribute handler
*/
resolve_handler_t *handler;
};