summaryrefslogtreecommitdiff
path: root/src/libipsec
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2013-01-02 14:18:20 +0100
committerYves-Alexis Perez <corsac@debian.org>2013-01-02 14:18:20 +0100
commitc1343b3278cdf99533b7902744d15969f9d6fdc1 (patch)
treed5ed3dc5677a59260ec41cd39bb284d3e94c91b3 /src/libipsec
parentb34738ed08c2227300d554b139e2495ca5da97d6 (diff)
downloadvyos-strongswan-c1343b3278cdf99533b7902744d15969f9d6fdc1.tar.gz
vyos-strongswan-c1343b3278cdf99533b7902744d15969f9d6fdc1.zip
Imported Upstream version 5.0.1
Diffstat (limited to 'src/libipsec')
-rw-r--r--src/libipsec/Android.mk38
-rw-r--r--src/libipsec/Makefile.am31
-rw-r--r--src/libipsec/Makefile.in780
-rw-r--r--src/libipsec/esp_context.c301
-rw-r--r--src/libipsec/esp_context.h110
-rw-r--r--src/libipsec/esp_packet.c468
-rw-r--r--src/libipsec/esp_packet.h151
-rw-r--r--src/libipsec/ip_packet.c193
-rw-r--r--src/libipsec/ip_packet.h96
-rw-r--r--src/libipsec/ipsec.c77
-rw-r--r--src/libipsec/ipsec.h83
-rw-r--r--src/libipsec/ipsec_event_listener.h48
-rw-r--r--src/libipsec/ipsec_event_relay.c193
-rw-r--r--src/libipsec/ipsec_event_relay.h79
-rw-r--r--src/libipsec/ipsec_policy.c212
-rw-r--r--src/libipsec/ipsec_policy.h140
-rw-r--r--src/libipsec/ipsec_policy_mgr.c286
-rw-r--r--src/libipsec/ipsec_policy_mgr.h119
-rw-r--r--src/libipsec/ipsec_processor.c324
-rw-r--r--src/libipsec/ipsec_processor.h115
-rw-r--r--src/libipsec/ipsec_sa.c234
-rw-r--r--src/libipsec/ipsec_sa.h169
-rw-r--r--src/libipsec/ipsec_sa_mgr.c626
-rw-r--r--src/libipsec/ipsec_sa_mgr.h167
24 files changed, 5040 insertions, 0 deletions
diff --git a/src/libipsec/Android.mk b/src/libipsec/Android.mk
new file mode 100644
index 000000000..81f4632ef
--- /dev/null
+++ b/src/libipsec/Android.mk
@@ -0,0 +1,38 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# copy-n-paste from Makefile.am
+LOCAL_SRC_FILES := \
+ipsec.c ipsec.h \
+esp_context.c esp_context.h \
+esp_packet.c esp_packet.h \
+ip_packet.c ip_packet.h \
+ipsec_event_listener.h \
+ipsec_event_relay.c ipsec_event_relay.h \
+ipsec_policy.c ipsec_policy.h \
+ipsec_policy_mgr.c ipsec_policy_mgr.h \
+ipsec_processor.c ipsec_processor.h \
+ipsec_sa.c ipsec_sa.h \
+ipsec_sa_mgr.c ipsec_sa_mgr.h
+
+# build libipsec ---------------------------------------------------------------
+
+LOCAL_C_INCLUDES += \
+ $(libvstr_PATH) \
+ $(strongswan_PATH)/src/include \
+ $(strongswan_PATH)/src/libstrongswan
+
+LOCAL_CFLAGS := $(strongswan_CFLAGS)
+
+LOCAL_MODULE := libipsec
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_SHARED_LIBRARIES += libstrongswan
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/src/libipsec/Makefile.am b/src/libipsec/Makefile.am
new file mode 100644
index 000000000..35b8d7916
--- /dev/null
+++ b/src/libipsec/Makefile.am
@@ -0,0 +1,31 @@
+ipseclib_LTLIBRARIES = libipsec.la
+
+libipsec_la_SOURCES = \
+ipsec.c ipsec.h \
+esp_context.c esp_context.h \
+esp_packet.c esp_packet.h \
+ip_packet.c ip_packet.h \
+ipsec_event_listener.h \
+ipsec_event_relay.c ipsec_event_relay.h \
+ipsec_policy.c ipsec_policy.h \
+ipsec_policy_mgr.c ipsec_policy_mgr.h \
+ipsec_processor.c ipsec_processor.h \
+ipsec_sa.c ipsec_sa.h \
+ipsec_sa_mgr.c ipsec_sa_mgr.h
+
+libipsec_la_LIBADD =
+
+INCLUDES = \
+ -I$(top_srcdir)/src/libstrongswan
+
+EXTRA_DIST = Android.mk
+
+# build optional plugins
+########################
+
+if MONOLITHIC
+SUBDIRS =
+else
+SUBDIRS = .
+endif
+
diff --git a/src/libipsec/Makefile.in b/src/libipsec/Makefile.in
new file mode 100644
index 000000000..6d984d8ab
--- /dev/null
+++ b/src/libipsec/Makefile.in
@@ -0,0 +1,780 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libipsec
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
+ $(top_srcdir)/m4/config/ltoptions.m4 \
+ $(top_srcdir)/m4/config/ltsugar.m4 \
+ $(top_srcdir)/m4/config/ltversion.m4 \
+ $(top_srcdir)/m4/config/lt~obsolete.m4 \
+ $(top_srcdir)/m4/macros/with.m4 \
+ $(top_srcdir)/m4/macros/enable-disable.m4 \
+ $(top_srcdir)/m4/macros/add-plugin.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+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)$(ipseclibdir)"
+LTLIBRARIES = $(ipseclib_LTLIBRARIES)
+libipsec_la_DEPENDENCIES =
+am_libipsec_la_OBJECTS = ipsec.lo esp_context.lo esp_packet.lo \
+ ip_packet.lo ipsec_event_relay.lo ipsec_policy.lo \
+ ipsec_policy_mgr.lo ipsec_processor.lo ipsec_sa.lo \
+ ipsec_sa_mgr.lo
+libipsec_la_OBJECTS = $(am_libipsec_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libipsec_la_SOURCES)
+DIST_SOURCES = $(libipsec_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = .
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BFDLIB = @BFDLIB@
+BTLIB = @BTLIB@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLIB = @DLLIB@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MYSQLCFLAG = @MYSQLCFLAG@
+MYSQLCONFIG = @MYSQLCONFIG@
+MYSQLLIB = @MYSQLLIB@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREADLIB = @PTHREADLIB@
+RANLIB = @RANLIB@
+RTLIB = @RTLIB@
+RUBY = @RUBY@
+RUBYINCLUDE = @RUBYINCLUDE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKLIB = @SOCKLIB@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+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@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_plugins = @c_plugins@
+charon_natt_port = @charon_natt_port@
+charon_plugins = @charon_plugins@
+charon_udp_port = @charon_udp_port@
+clearsilver_LIBS = @clearsilver_LIBS@
+datadir = @datadir@
+datarootdir = @datarootdir@
+dbusservicedir = @dbusservicedir@
+dev_headers = @dev_headers@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gtk_CFLAGS = @gtk_CFLAGS@
+gtk_LIBS = @gtk_LIBS@
+h_plugins = @h_plugins@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+imcvdir = @imcvdir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsec_script = @ipsec_script@
+ipsec_script_upper = @ipsec_script_upper@
+ipsecdir = @ipsecdir@
+ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
+ipsecuser = @ipsecuser@
+libdir = @libdir@
+libexecdir = @libexecdir@
+linux_headers = @linux_headers@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+maemo_CFLAGS = @maemo_CFLAGS@
+maemo_LIBS = @maemo_LIBS@
+manager_plugins = @manager_plugins@
+mandir = @mandir@
+medsrv_plugins = @medsrv_plugins@
+mkdir_p = @mkdir_p@
+nm_CFLAGS = @nm_CFLAGS@
+nm_LIBS = @nm_LIBS@
+nm_ca_dir = @nm_ca_dir@
+nm_plugins = @nm_plugins@
+oldincludedir = @oldincludedir@
+openac_plugins = @openac_plugins@
+p_plugins = @p_plugins@
+pcsclite_CFLAGS = @pcsclite_CFLAGS@
+pcsclite_LIBS = @pcsclite_LIBS@
+pdfdir = @pdfdir@
+piddir = @piddir@
+pki_plugins = @pki_plugins@
+plugindir = @plugindir@
+pool_plugins = @pool_plugins@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+random_device = @random_device@
+resolv_conf = @resolv_conf@
+routing_table = @routing_table@
+routing_table_prio = @routing_table_prio@
+s_plugins = @s_plugins@
+sbindir = @sbindir@
+scepclient_plugins = @scepclient_plugins@
+scripts_plugins = @scripts_plugins@
+sharedstatedir = @sharedstatedir@
+soup_CFLAGS = @soup_CFLAGS@
+soup_LIBS = @soup_LIBS@
+srcdir = @srcdir@
+starter_plugins = @starter_plugins@
+strongswan_conf = @strongswan_conf@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+urandom_device = @urandom_device@
+xml_CFLAGS = @xml_CFLAGS@
+xml_LIBS = @xml_LIBS@
+ipseclib_LTLIBRARIES = libipsec.la
+libipsec_la_SOURCES = \
+ipsec.c ipsec.h \
+esp_context.c esp_context.h \
+esp_packet.c esp_packet.h \
+ip_packet.c ip_packet.h \
+ipsec_event_listener.h \
+ipsec_event_relay.c ipsec_event_relay.h \
+ipsec_policy.c ipsec_policy.h \
+ipsec_policy_mgr.c ipsec_policy_mgr.h \
+ipsec_processor.c ipsec_processor.h \
+ipsec_sa.c ipsec_sa.h \
+ipsec_sa_mgr.c ipsec_sa_mgr.h
+
+libipsec_la_LIBADD =
+INCLUDES = \
+ -I$(top_srcdir)/src/libstrongswan
+
+EXTRA_DIST = Android.mk
+@MONOLITHIC_FALSE@SUBDIRS = .
+
+# build optional plugins
+########################
+@MONOLITHIC_TRUE@SUBDIRS =
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libipsec/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libipsec/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ 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)$(ipseclibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \
+ }
+
+uninstall-ipseclibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @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)$(ipseclibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \
+ done
+
+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
+libipsec.la: $(libipsec_la_OBJECTS) $(libipsec_la_DEPENDENCIES)
+ $(LINK) -rpath $(ipseclibdir) $(libipsec_la_OBJECTS) $(libipsec_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esp_context.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esp_packet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip_packet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_event_relay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_policy.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_policy_mgr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_processor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_sa.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_sa_mgr.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(ipseclibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-ipseclibLTLIBRARIES
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+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-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-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.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libipsec/esp_context.c b/src/libipsec/esp_context.c
new file mode 100644
index 000000000..dc3ad3f8b
--- /dev/null
+++ b/src/libipsec/esp_context.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <limits.h>
+#include <stdint.h>
+
+#include "esp_context.h"
+
+#include <library.h>
+#include <debug.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+
+/**
+ * Should be a multiple of 8
+ */
+#define ESP_DEFAULT_WINDOW_SIZE 128
+
+typedef struct private_esp_context_t private_esp_context_t;
+
+/**
+ * Private additions to esp_context_t.
+ */
+struct private_esp_context_t {
+
+ /**
+ * Public members
+ */
+ esp_context_t public;
+
+ /**
+ * Crypter used to encrypt/decrypt ESP packets
+ */
+ crypter_t *crypter;
+
+ /**
+ * Signer to authenticate ESP packets
+ */
+ signer_t *signer;
+
+ /**
+ * The highest sequence number that was successfully verified
+ * and authenticated, or assigned in an outbound context
+ */
+ u_int32_t last_seqno;
+
+ /**
+ * The bit in the window of the highest authenticated sequence number
+ */
+ u_int seqno_index;
+
+ /**
+ * The size of the anti-replay window (in bits)
+ */
+ u_int window_size;
+
+ /**
+ * The anti-replay window buffer
+ */
+ chunk_t window;
+
+ /**
+ * TRUE in case of an inbound ESP context
+ */
+ bool inbound;
+};
+
+/**
+ * Set or unset a bit in the window.
+ */
+static inline void set_window_bit(private_esp_context_t *this,
+ u_int index, bool set)
+{
+ u_int i = index / CHAR_BIT;
+
+ if (set)
+ {
+ this->window.ptr[i] |= 1 << (index % CHAR_BIT);
+ }
+ else
+ {
+ this->window.ptr[i] &= ~(1 << (index % CHAR_BIT));
+ }
+}
+
+/**
+ * Get a bit from the window.
+ */
+static inline bool get_window_bit(private_esp_context_t *this, u_int index)
+{
+ u_int i = index / CHAR_BIT;
+
+ return this->window.ptr[i] & (1 << index % CHAR_BIT);
+}
+
+/**
+ * Returns TRUE if the supplied seqno is not already marked in the window
+ */
+static bool check_window(private_esp_context_t *this, u_int32_t seqno)
+{
+ u_int offset;
+
+ offset = this->last_seqno - seqno;
+ offset = (this->seqno_index - offset) % this->window_size;
+ return !get_window_bit(this, offset);
+}
+
+METHOD(esp_context_t, verify_seqno, bool,
+ private_esp_context_t *this, u_int32_t seqno)
+{
+ if (!this->inbound)
+ {
+ return FALSE;
+ }
+
+ if (seqno > this->last_seqno)
+ { /* |----------------------------------------|
+ * <---------^ ^ or <---------^ ^
+ * WIN H S WIN H S
+ */
+ return TRUE;
+ }
+ else if (seqno > 0 && this->window_size > this->last_seqno - seqno)
+ { /* |----------------------------------------|
+ * <---------^ or <---------^
+ * WIN ^ H WIN ^ H
+ * S S
+ */
+ return check_window(this, seqno);
+ }
+ else
+ { /* |----------------------------------------|
+ * ^ <---------^
+ * S WIN H
+ */
+ return FALSE;
+ }
+}
+
+METHOD(esp_context_t, set_authenticated_seqno, void,
+ private_esp_context_t *this, u_int32_t seqno)
+{
+ u_int i, shift;
+
+ if (!this->inbound)
+ {
+ return;
+ }
+
+ if (seqno > this->last_seqno)
+ { /* shift the window to the new highest authenticated seqno */
+ shift = seqno - this->last_seqno;
+ shift = shift < this->window_size ? shift : this->window_size;
+ for (i = 0; i < shift; ++i)
+ {
+ this->seqno_index = (this->seqno_index + 1) % this->window_size;
+ set_window_bit(this, this->seqno_index, FALSE);
+ }
+ set_window_bit(this, this->seqno_index, TRUE);
+ this->last_seqno = seqno;
+ }
+ else
+ { /* seqno is inside the window, set the corresponding window bit */
+ i = this->last_seqno - seqno;
+ set_window_bit(this, (this->seqno_index - i) % this->window_size, TRUE);
+ }
+}
+
+METHOD(esp_context_t, get_seqno, u_int32_t,
+ private_esp_context_t *this)
+{
+ return this->last_seqno;
+}
+
+METHOD(esp_context_t, next_seqno, bool,
+ private_esp_context_t *this, u_int32_t *seqno)
+{
+ if (this->inbound || this->last_seqno == UINT32_MAX)
+ { /* inbound or segno would cycle */
+ return FALSE;
+ }
+ *seqno = ++this->last_seqno;
+ return TRUE;
+}
+
+METHOD(esp_context_t, get_signer, signer_t *,
+ private_esp_context_t *this)
+{
+ return this->signer;
+}
+
+METHOD(esp_context_t, get_crypter, crypter_t *,
+ private_esp_context_t *this)
+{
+ return this->crypter;
+}
+
+METHOD(esp_context_t, destroy, void,
+ private_esp_context_t *this)
+{
+ chunk_free(&this->window);
+ DESTROY_IF(this->crypter);
+ DESTROY_IF(this->signer);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
+ int int_alg, chunk_t int_key, bool inbound)
+{
+ private_esp_context_t *this;
+
+ INIT(this,
+ .public = {
+ .get_crypter = _get_crypter,
+ .get_signer = _get_signer,
+ .get_seqno = _get_seqno,
+ .next_seqno = _next_seqno,
+ .verify_seqno = _verify_seqno,
+ .set_authenticated_seqno = _set_authenticated_seqno,
+ .destroy = _destroy,
+ },
+ .inbound = inbound,
+ .window_size = ESP_DEFAULT_WINDOW_SIZE,
+ );
+
+ switch(enc_alg)
+ {
+ case ENCR_AES_CBC:
+ this->crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
+ enc_key.len);
+ break;
+ default:
+ break;
+ }
+ if (!this->crypter)
+ {
+ DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
+ "algorithm");
+ destroy(this);
+ return NULL;
+ }
+ if (!this->crypter->set_key(this->crypter, enc_key))
+ {
+ DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
+ "failed");
+ destroy(this);
+ return NULL;
+ }
+
+ switch(int_alg)
+ {
+ case AUTH_HMAC_SHA1_96:
+ case AUTH_HMAC_SHA2_256_128:
+ case AUTH_HMAC_SHA2_384_192:
+ case AUTH_HMAC_SHA2_512_256:
+ this->signer = lib->crypto->create_signer(lib->crypto, int_alg);
+ break;
+ default:
+ break;
+ }
+ if (!this->signer)
+ {
+ DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
+ "algorithm");
+ destroy(this);
+ return NULL;
+ }
+ if (!this->signer->set_key(this->signer, int_key))
+ {
+ DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
+ "failed");
+ destroy(this);
+ return NULL;
+ }
+
+ if (inbound)
+ {
+ this->window = chunk_alloc(this->window_size / CHAR_BIT + 1);
+ memset(this->window.ptr, 0, this->window.len);
+ }
+ return &this->public;
+}
+
+
diff --git a/src/libipsec/esp_context.h b/src/libipsec/esp_context.h
new file mode 100644
index 000000000..db247dced
--- /dev/null
+++ b/src/libipsec/esp_context.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup esp_context esp_context
+ * @{ @ingroup libipsec
+ */
+
+#ifndef ESP_CONTEXT_H_
+#define ESP_CONTEXT_H_
+
+#include <library.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+
+typedef struct esp_context_t esp_context_t;
+
+/**
+ * ESP context, handles sequence numbers and maintains cryptographic primitives
+ */
+struct esp_context_t {
+
+ /**
+ * Get the crypter.
+ *
+ * @return crypter
+ */
+ crypter_t *(*get_crypter)(esp_context_t *this);
+
+ /**
+ * Get the signer.
+ *
+ * @return signer
+ */
+ signer_t *(*get_signer)(esp_context_t *this);
+
+ /**
+ * Get the current outbound ESP sequence number or the highest authenticated
+ * inbound sequence number.
+ *
+ * @return current sequence number, in host byte order
+ */
+ u_int32_t (*get_seqno)(esp_context_t *this);
+
+ /**
+ * Allocate the next outbound ESP sequence number.
+ *
+ * @param seqno the sequence number, in host byte order
+ * @return FALSE if the sequence number cycled or inbound context
+ */
+ bool (*next_seqno)(esp_context_t *this, u_int32_t *seqno);
+
+ /**
+ * Verify an ESP sequence number. Checks whether a packet with this
+ * sequence number was already received, using the anti-replay window.
+ * This operation does not modify the internal state. After the sequence
+ * number is successfully verified and the ESP packet is authenticated,
+ * set_authenticated_seqno() should be called.
+ *
+ * @param seqno the sequence number to verify, in host byte order
+ * @return TRUE when sequence number is valid
+ */
+ bool (*verify_seqno)(esp_context_t *this, u_int32_t seqno);
+
+ /**
+ * Adds a sequence number that was successfully verified and
+ * authenticated. A user MUST call verify_seqno() immediately before
+ * calling this method.
+ *
+ * @param seqno verified and authenticated seq number in host byte order
+ */
+ void (*set_authenticated_seqno)(esp_context_t *this,
+ u_int32_t seqno);
+
+ /**
+ * Destroy an esp_context_t
+ */
+ void (*destroy)(esp_context_t *this);
+
+};
+
+/**
+ * Create an esp_context_t instance
+ *
+ * @param enc_alg encryption algorithm
+ * @param enc_key encryption key
+ * @param int_alg integrity protection algorithm
+ * @param int_key integrity protection key
+ * @param inbound TRUE to create an inbound ESP context
+ * @return ESP context instance, or NULL if creation fails
+ */
+esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key, int int_alg,
+ chunk_t int_key, bool inbound);
+
+#endif /** ESP_CONTEXT_H_ @}*/
+
diff --git a/src/libipsec/esp_packet.c b/src/libipsec/esp_packet.c
new file mode 100644
index 000000000..bfcab95eb
--- /dev/null
+++ b/src/libipsec/esp_packet.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "esp_packet.h"
+
+#include <library.h>
+#include <debug.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+#include <bio/bio_reader.h>
+#include <bio/bio_writer.h>
+
+#include <netinet/in.h>
+
+typedef struct private_esp_packet_t private_esp_packet_t;
+
+/**
+ * Private additions to esp_packet_t.
+ */
+struct private_esp_packet_t {
+
+ /**
+ * Public members
+ */
+ esp_packet_t public;
+
+ /**
+ * Raw ESP packet
+ */
+ packet_t *packet;
+
+ /**
+ * Payload of this packet
+ */
+ ip_packet_t *payload;
+
+ /**
+ * Next Header info (e.g. IPPROTO_IPIP)
+ */
+ u_int8_t next_header;
+
+};
+
+/**
+ * Forward declaration for clone()
+ */
+static private_esp_packet_t *esp_packet_create_internal(packet_t *packet);
+
+METHOD(packet_t, set_source, void,
+ private_esp_packet_t *this, host_t *src)
+{
+ return this->packet->set_source(this->packet, src);
+}
+
+METHOD2(esp_packet_t, packet_t, get_source, host_t*,
+ private_esp_packet_t *this)
+{
+ return this->packet->get_source(this->packet);
+}
+
+METHOD(packet_t, set_destination, void,
+ private_esp_packet_t *this, host_t *dst)
+{
+ return this->packet->set_destination(this->packet, dst);
+}
+
+METHOD2(esp_packet_t, packet_t, get_destination, host_t*,
+ private_esp_packet_t *this)
+{
+ return this->packet->get_destination(this->packet);
+}
+
+METHOD(packet_t, get_data, chunk_t,
+ private_esp_packet_t *this)
+{
+ return this->packet->get_data(this->packet);
+}
+
+METHOD(packet_t, set_data, void,
+ private_esp_packet_t *this, chunk_t data)
+{
+ return this->packet->set_data(this->packet, data);
+}
+
+METHOD(packet_t, skip_bytes, void,
+ private_esp_packet_t *this, size_t bytes)
+{
+ return this->packet->skip_bytes(this->packet, bytes);
+}
+
+METHOD(packet_t, clone, packet_t*,
+ private_esp_packet_t *this)
+{
+ private_esp_packet_t *pkt;
+
+ pkt = esp_packet_create_internal(this->packet->clone(this->packet));
+ pkt->payload = this->payload ? this->payload->clone(this->payload) : NULL;
+ pkt->next_header = this->next_header;
+ return &pkt->public.packet;
+}
+
+METHOD(esp_packet_t, parse_header, bool,
+ private_esp_packet_t *this, u_int32_t *spi)
+{
+ bio_reader_t *reader;
+ u_int32_t seq;
+
+ reader = bio_reader_create(this->packet->get_data(this->packet));
+ if (!reader->read_uint32(reader, spi) ||
+ !reader->read_uint32(reader, &seq))
+ {
+ DBG1(DBG_ESP, "failed to parse ESP header: invalid length");
+ reader->destroy(reader);
+ return FALSE;
+ }
+ reader->destroy(reader);
+
+ DBG2(DBG_ESP, "parsed ESP header with SPI %.8x [seq %u]", *spi, seq);
+ *spi = htonl(*spi);
+ return TRUE;
+}
+
+/**
+ * Check padding as specified in RFC 4303
+ */
+static bool check_padding(chunk_t padding)
+{
+ size_t i;
+
+ for (i = 0; i < padding.len; ++i)
+ {
+ if (padding.ptr[i] != (u_int8_t)(i + 1))
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Remove the padding from the payload and set the next header info
+ */
+static bool remove_padding(private_esp_packet_t *this, chunk_t plaintext)
+{
+ u_int8_t next_header, pad_length;
+ chunk_t padding, payload;
+ bio_reader_t *reader;
+
+ reader = bio_reader_create(plaintext);
+ if (!reader->read_uint8_end(reader, &next_header) ||
+ !reader->read_uint8_end(reader, &pad_length))
+ {
+ DBG1(DBG_ESP, "parsing ESP payload failed: invalid length");
+ goto failed;
+ }
+ if (!reader->read_data_end(reader, pad_length, &padding) ||
+ !check_padding(padding))
+ {
+ DBG1(DBG_ESP, "parsing ESP payload failed: invalid padding");
+ goto failed;
+ }
+ this->payload = ip_packet_create(reader->peek(reader));
+ reader->destroy(reader);
+ if (!this->payload)
+ {
+ DBG1(DBG_ESP, "parsing ESP payload failed: unsupported payload");
+ return FALSE;
+ }
+ this->next_header = next_header;
+ payload = this->payload->get_encoding(this->payload);
+
+ DBG3(DBG_ESP, "ESP payload:\n payload %B\n padding %B\n "
+ "padding length = %hhu, next header = %hhu", &payload, &padding,
+ pad_length, this->next_header);
+ return TRUE;
+
+failed:
+ reader->destroy(reader);
+ chunk_free(&plaintext);
+ return FALSE;
+}
+
+METHOD(esp_packet_t, decrypt, status_t,
+ private_esp_packet_t *this, esp_context_t *esp_context)
+{
+ bio_reader_t *reader;
+ u_int32_t spi, seq;
+ chunk_t data, iv, icv, ciphertext, plaintext;
+ crypter_t *crypter;
+ signer_t *signer;
+
+ DESTROY_IF(this->payload);
+ this->payload = NULL;
+
+ data = this->packet->get_data(this->packet);
+ crypter = esp_context->get_crypter(esp_context);
+ signer = esp_context->get_signer(esp_context);
+
+ reader = bio_reader_create(data);
+ if (!reader->read_uint32(reader, &spi) ||
+ !reader->read_uint32(reader, &seq) ||
+ !reader->read_data(reader, crypter->get_iv_size(crypter), &iv) ||
+ !reader->read_data_end(reader, signer->get_block_size(signer), &icv) ||
+ reader->remaining(reader) % crypter->get_block_size(crypter))
+ {
+ DBG1(DBG_ESP, "ESP decryption failed: invalid length");
+ return PARSE_ERROR;
+ }
+ ciphertext = reader->peek(reader);
+ reader->destroy(reader);
+
+ if (!esp_context->verify_seqno(esp_context, seq))
+ {
+ DBG1(DBG_ESP, "ESP sequence number verification failed:\n "
+ "src %H, dst %H, SPI %.8x [seq %u]",
+ get_source(this), get_destination(this), spi, seq);
+ return VERIFY_ERROR;
+ }
+ DBG3(DBG_ESP, "ESP decryption:\n SPI %.8x [seq %u]\n IV %B\n "
+ "encrypted %B\n ICV %B", spi, seq, &iv, &ciphertext, &icv);
+
+ if (!signer->get_signature(signer, chunk_create(data.ptr, 8), NULL) ||
+ !signer->get_signature(signer, iv, NULL) ||
+ !signer->verify_signature(signer, ciphertext, icv))
+ {
+ DBG1(DBG_ESP, "ICV verification failed!");
+ return FAILED;
+ }
+ esp_context->set_authenticated_seqno(esp_context, seq);
+
+ if (!crypter->decrypt(crypter, ciphertext, iv, &plaintext))
+ {
+ DBG1(DBG_ESP, "ESP decryption failed");
+ return FAILED;
+ }
+
+ if (!remove_padding(this, plaintext))
+ {
+ return PARSE_ERROR;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Generate the padding as specified in RFC4303
+ */
+static void generate_padding(chunk_t padding)
+{
+ size_t i;
+
+ for (i = 0; i < padding.len; ++i)
+ {
+ padding.ptr[i] = (u_int8_t)(i + 1);
+ }
+}
+
+METHOD(esp_packet_t, encrypt, status_t,
+ private_esp_packet_t *this, esp_context_t *esp_context, u_int32_t spi)
+{
+ chunk_t iv, icv, padding, payload, ciphertext, auth_data;
+ bio_writer_t *writer;
+ u_int32_t next_seqno;
+ size_t blocksize, plainlen;
+ crypter_t *crypter;
+ signer_t *signer;
+ rng_t *rng;
+
+ this->packet->set_data(this->packet, chunk_empty);
+
+ if (!esp_context->next_seqno(esp_context, &next_seqno))
+ {
+ DBG1(DBG_ESP, "ESP encapsulation failed: sequence numbers cycled");
+ return FAILED;
+ }
+
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng)
+ {
+ DBG1(DBG_ESP, "ESP encryption failed: could not find RNG");
+ return NOT_FOUND;
+ }
+ crypter = esp_context->get_crypter(esp_context);
+ signer = esp_context->get_signer(esp_context);
+
+ blocksize = crypter->get_block_size(crypter);
+ iv.len = crypter->get_iv_size(crypter);
+ icv.len = signer->get_block_size(signer);
+
+ /* plaintext = payload, padding, pad_length, next_header */
+ payload = this->payload ? this->payload->get_encoding(this->payload)
+ : chunk_empty;
+ plainlen = payload.len + 2;
+ padding.len = blocksize - (plainlen % blocksize);
+ plainlen += padding.len;
+
+ /* len = spi, seq, IV, plaintext, ICV */
+ writer = bio_writer_create(2 * sizeof(u_int32_t) + iv.len + plainlen +
+ icv.len);
+ writer->write_uint32(writer, ntohl(spi));
+ writer->write_uint32(writer, next_seqno);
+
+ iv = writer->skip(writer, iv.len);
+ if (!rng->get_bytes(rng, iv.len, iv.ptr))
+ {
+ DBG1(DBG_ESP, "ESP encryption failed: could not generate IV");
+ writer->destroy(writer);
+ rng->destroy(rng);
+ return FAILED;
+ }
+ rng->destroy(rng);
+
+ /* plain-/ciphertext will start here */
+ ciphertext = writer->get_buf(writer);
+ ciphertext.ptr += ciphertext.len;
+ ciphertext.len = plainlen;
+
+ writer->write_data(writer, payload);
+
+ padding = writer->skip(writer, padding.len);
+ generate_padding(padding);
+
+ writer->write_uint8(writer, padding.len);
+ writer->write_uint8(writer, this->next_header);
+
+ DBG3(DBG_ESP, "ESP before encryption:\n payload = %B\n padding = %B\n "
+ "padding length = %hhu, next header = %hhu", &payload, &padding,
+ (u_int8_t)padding.len, this->next_header);
+
+ /* encrypt the content inline */
+ if (!crypter->encrypt(crypter, ciphertext, iv, NULL))
+ {
+ DBG1(DBG_ESP, "ESP encryption failed");
+ writer->destroy(writer);
+ return FAILED;
+ }
+
+ /* calculate signature */
+ auth_data = writer->get_buf(writer);
+ icv = writer->skip(writer, icv.len);
+ if (!signer->get_signature(signer, auth_data, icv.ptr))
+ {
+ DBG1(DBG_ESP, "ESP encryption failed: signature generation failed");
+ writer->destroy(writer);
+ return FAILED;
+ }
+
+ DBG3(DBG_ESP, "ESP packet:\n SPI %.8x [seq %u]\n IV %B\n "
+ "encrypted %B\n ICV %B", ntohl(spi), next_seqno, &iv,
+ &ciphertext, &icv);
+
+ this->packet->set_data(this->packet, writer->extract_buf(writer));
+ writer->destroy(writer);
+ return SUCCESS;
+}
+
+METHOD(esp_packet_t, get_next_header, u_int8_t,
+ private_esp_packet_t *this)
+{
+ return this->next_header;
+}
+
+METHOD(esp_packet_t, get_payload, ip_packet_t*,
+ private_esp_packet_t *this)
+{
+ return this->payload;
+}
+
+METHOD(esp_packet_t, extract_payload, ip_packet_t*,
+ private_esp_packet_t *this)
+{
+ ip_packet_t *payload;
+
+ payload = this->payload;
+ this->payload = NULL;
+ return payload;
+}
+
+METHOD2(esp_packet_t, packet_t, destroy, void,
+ private_esp_packet_t *this)
+{
+ DESTROY_IF(this->payload);
+ this->packet->destroy(this->packet);
+ free(this);
+}
+
+static private_esp_packet_t *esp_packet_create_internal(packet_t *packet)
+{
+ private_esp_packet_t *this;
+
+ INIT(this,
+ .public = {
+ .packet = {
+ .set_source = _set_source,
+ .get_source = _get_source,
+ .set_destination = _set_destination,
+ .get_destination = _get_destination,
+ .get_data = _get_data,
+ .set_data = _set_data,
+ .skip_bytes = _skip_bytes,
+ .clone = _clone,
+ .destroy = _destroy,
+ },
+ .get_source = _get_source,
+ .get_destination = _get_destination,
+ .get_next_header = _get_next_header,
+ .parse_header = _parse_header,
+ .decrypt = _decrypt,
+ .encrypt = _encrypt,
+ .get_payload = _get_payload,
+ .extract_payload = _extract_payload,
+ .destroy = _destroy,
+ },
+ .packet = packet,
+ .next_header = IPPROTO_NONE,
+ );
+ return this;
+}
+
+/**
+ * Described in header.
+ */
+esp_packet_t *esp_packet_create_from_packet(packet_t *packet)
+{
+ private_esp_packet_t *this;
+
+ this = esp_packet_create_internal(packet);
+
+ return &this->public;
+}
+
+/**
+ * Described in header.
+ */
+esp_packet_t *esp_packet_create_from_payload(host_t *src, host_t *dst,
+ ip_packet_t *payload)
+{
+ private_esp_packet_t *this;
+ packet_t *packet;
+
+ packet = packet_create_from_data(src, dst, chunk_empty);
+ this = esp_packet_create_internal(packet);
+ this->payload = payload;
+ if (payload)
+ {
+ this->next_header = payload->get_version(payload) == 4 ? IPPROTO_IPIP
+ : IPPROTO_IPV6;
+ }
+ else
+ {
+ this->next_header = IPPROTO_NONE;
+ }
+ return &this->public;
+}
diff --git a/src/libipsec/esp_packet.h b/src/libipsec/esp_packet.h
new file mode 100644
index 000000000..a1d1602c1
--- /dev/null
+++ b/src/libipsec/esp_packet.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup esp_packet esp_packet
+ * @{ @ingroup libipsec
+ */
+
+#ifndef ESP_PACKET_H_
+#define ESP_PACKET_H_
+
+#include "ip_packet.h"
+#include "esp_context.h"
+
+#include <library.h>
+#include <utils/host.h>
+#include <utils/packet.h>
+
+typedef struct esp_packet_t esp_packet_t;
+
+/**
+ * ESP packet
+ */
+struct esp_packet_t {
+
+ /**
+ * Implements packet_t interface to access the raw ESP packet
+ */
+ packet_t packet;
+
+ /**
+ * Get the source address of this packet
+ *
+ * @return source host
+ */
+ host_t *(*get_source)(esp_packet_t *this);
+
+ /**
+ * Get the destination address of this packet
+ *
+ * @return destination host
+ */
+ host_t *(*get_destination)(esp_packet_t *this);
+
+ /**
+ * Parse the packet header before decryption. Tries to read the SPI
+ * from the packet to find a corresponding SA.
+ *
+ * @param spi parsed SPI, in network byte order
+ * @return TRUE when successful, FALSE otherwise (e.g. when the
+ * length of the packet is invalid)
+ */
+ bool (*parse_header)(esp_packet_t *this, u_int32_t *spi);
+
+ /**
+ * Authenticate and decrypt the packet. Also verifies the sequence number
+ * using the supplied ESP context and updates the anti-replay window.
+ *
+ * @param esp_context ESP context of corresponding inbound IPsec SA
+ * @return - SUCCESS if successfully authenticated,
+ * decrypted and parsed
+ * - PARSE_ERROR if the length of the packet or the
+ * padding is invalid
+ * - VERIFY_ERROR if the sequence number
+ * verification failed
+ * - FAILED if the ICV (MAC) check or the actual
+ * decryption failed
+ */
+ status_t (*decrypt)(esp_packet_t *this, esp_context_t *esp_context);
+
+ /**
+ * Encapsulate and encrypt the packet. The sequence number will be generated
+ * using the supplied ESP context.
+ *
+ * @param esp_context ESP context of corresponding outbound IPsec SA
+ * @param spi SPI value to use, in network byte order
+ * @return - SUCCESS if encrypted
+ * - FAILED if sequence number cycled or any of the
+ * cryptographic functions failed
+ * - NOT_FOUND if no suitable RNG could be found
+ */
+ status_t (*encrypt)(esp_packet_t *this, esp_context_t *esp_context,
+ u_int32_t spi);
+
+ /**
+ * Get the next header field of a packet.
+ *
+ * @note Packet has to be in the decrypted state.
+ *
+ * @return next header field
+ */
+ u_int8_t (*get_next_header)(esp_packet_t *this);
+
+ /**
+ * Get the plaintext payload of this packet.
+ *
+ * @return plaintext payload (internal data),
+ * NULL if not decrypted
+ */
+ ip_packet_t *(*get_payload)(esp_packet_t *this);
+
+ /**
+ * Extract the plaintext payload from this packet.
+ *
+ * @return plaintext payload (has to be destroyed),
+ * NULL if not decrypted
+ */
+ ip_packet_t *(*extract_payload)(esp_packet_t *this);
+
+ /**
+ * Destroy an esp_packet_t
+ */
+ void (*destroy)(esp_packet_t *this);
+
+};
+
+/**
+ * Create an ESP packet out of data from the wire.
+ *
+ * @param packet the packet data as received, gets owned
+ * @return esp_packet_t instance
+ */
+esp_packet_t *esp_packet_create_from_packet(packet_t *packet);
+
+/**
+ * Create an ESP packet from a plaintext payload
+ *
+ * @param src source address
+ * @param dst destination address
+ * @param payload plaintext payload, gets owned
+ * @return esp_packet_t instance
+ */
+esp_packet_t *esp_packet_create_from_payload(host_t *src, host_t *dst,
+ ip_packet_t *payload);
+
+#endif /** ESP_PACKET_H_ @}*/
+
diff --git a/src/libipsec/ip_packet.c b/src/libipsec/ip_packet.c
new file mode 100644
index 000000000..096ca33a8
--- /dev/null
+++ b/src/libipsec/ip_packet.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "ip_packet.h"
+
+#include <library.h>
+#include <debug.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#ifdef HAVE_NETINET_IP6_H
+#include <netinet/ip6.h>
+#endif
+
+typedef struct private_ip_packet_t private_ip_packet_t;
+
+/**
+ * Private additions to ip_packet_t.
+ */
+struct private_ip_packet_t {
+
+ /**
+ * Public members
+ */
+ ip_packet_t public;
+
+ /**
+ * Source address
+ */
+ host_t *src;
+
+ /**
+ * Destination address
+ */
+ host_t *dst;
+
+ /**
+ * IP packet
+ */
+ chunk_t packet;
+
+ /**
+ * IP version
+ */
+ u_int8_t version;
+
+ /**
+ * Protocol|Next Header field
+ */
+ u_int8_t next_header;
+
+};
+
+METHOD(ip_packet_t, get_version, u_int8_t,
+ private_ip_packet_t *this)
+{
+ return this->version;
+}
+
+METHOD(ip_packet_t, get_source, host_t*,
+ private_ip_packet_t *this)
+{
+ return this->src;
+}
+
+METHOD(ip_packet_t, get_destination, host_t*,
+ private_ip_packet_t *this)
+{
+ return this->dst;
+}
+
+METHOD(ip_packet_t, get_encoding, chunk_t,
+ private_ip_packet_t *this)
+{
+ return this->packet;
+}
+
+METHOD(ip_packet_t, get_next_header, u_int8_t,
+ private_ip_packet_t *this)
+{
+ return this->next_header;
+}
+
+METHOD(ip_packet_t, clone, ip_packet_t*,
+ private_ip_packet_t *this)
+{
+ return ip_packet_create(this->packet);
+}
+
+METHOD(ip_packet_t, destroy, void,
+ private_ip_packet_t *this)
+{
+ this->src->destroy(this->src);
+ this->dst->destroy(this->dst);
+ chunk_free(&this->packet);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+ip_packet_t *ip_packet_create(chunk_t packet)
+{
+ private_ip_packet_t *this;
+ u_int8_t version, next_header;
+ host_t *src, *dst;
+
+ if (packet.len < 1)
+ {
+ DBG1(DBG_ESP, "IP packet too short");
+ goto failed;
+ }
+
+ version = (packet.ptr[0] & 0xf0) >> 4;
+
+ switch (version)
+ {
+ case 4:
+ {
+ struct ip *ip;
+
+ if (packet.len < sizeof(struct ip))
+ {
+ DBG1(DBG_ESP, "IPv4 packet too short");
+ goto failed;
+ }
+ ip = (struct ip*)packet.ptr;
+ src = host_create_from_chunk(AF_INET,
+ chunk_from_thing(ip->ip_src), 0);
+ dst = host_create_from_chunk(AF_INET,
+ chunk_from_thing(ip->ip_dst), 0);
+ next_header = ip->ip_p;
+ break;
+ }
+#ifdef HAVE_NETINET_IP6_H
+ case 6:
+ {
+ struct ip6_hdr *ip;
+
+ if (packet.len < sizeof(struct ip6_hdr))
+ {
+ DBG1(DBG_ESP, "IPv6 packet too short");
+ goto failed;
+ }
+ ip = (struct ip6_hdr*)packet.ptr;
+ src = host_create_from_chunk(AF_INET6,
+ chunk_from_thing(ip->ip6_src), 0);
+ dst = host_create_from_chunk(AF_INET6,
+ chunk_from_thing(ip->ip6_dst), 0);
+ next_header = ip->ip6_nxt;
+ break;
+ }
+#endif /* HAVE_NETINET_IP6_H */
+ default:
+ DBG1(DBG_ESP, "unsupported IP version");
+ goto failed;
+ }
+
+ INIT(this,
+ .public = {
+ .get_version = _get_version,
+ .get_source = _get_source,
+ .get_destination = _get_destination,
+ .get_next_header = _get_next_header,
+ .get_encoding = _get_encoding,
+ .clone = _clone,
+ .destroy = _destroy,
+ },
+ .src = src,
+ .dst = dst,
+ .packet = packet,
+ .version = version,
+ .next_header = next_header,
+ );
+ return &this->public;
+
+failed:
+ chunk_free(&packet);
+ return NULL;
+}
diff --git a/src/libipsec/ip_packet.h b/src/libipsec/ip_packet.h
new file mode 100644
index 000000000..b4fc298ff
--- /dev/null
+++ b/src/libipsec/ip_packet.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ip_packet ip_packet
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IP_PACKET_H_
+#define IP_PACKET_H_
+
+#include <library.h>
+#include <utils/host.h>
+#include <utils/packet.h>
+
+typedef struct ip_packet_t ip_packet_t;
+
+/**
+ * IP packet
+ */
+struct ip_packet_t {
+
+ /**
+ * IP version of this packet
+ *
+ * @return ip version
+ */
+ u_int8_t (*get_version)(ip_packet_t *this);
+
+ /**
+ * Get the source address of this packet
+ *
+ * @return source host
+ */
+ host_t *(*get_source)(ip_packet_t *this);
+
+ /**
+ * Get the destination address of this packet
+ *
+ * @return destination host
+ */
+ host_t *(*get_destination)(ip_packet_t *this);
+
+ /**
+ * Get the protocol (IPv4) or next header (IPv6) field of this packet.
+ *
+ * @return protocol|next header field
+ */
+ u_int8_t (*get_next_header)(ip_packet_t *this);
+
+ /**
+ * Get the complete IP packet (including the header)
+ *
+ * @return IP packet (internal data)
+ */
+ chunk_t (*get_encoding)(ip_packet_t *this);
+
+ /**
+ * Clone the IP packet
+ *
+ * @return clone of the packet
+ */
+ ip_packet_t *(*clone)(ip_packet_t *this);
+
+ /**
+ * Destroy an ip_packet_t
+ */
+ void (*destroy)(ip_packet_t *this);
+
+};
+
+/**
+ * Create an IP packet out of data from the wire (or decapsulated from another
+ * packet).
+ *
+ * @note The raw IP packet gets either owned by the new object, or destroyed,
+ * if the data is invalid.
+ *
+ * @param packet the IP packet (including header), gets owned
+ * @return ip_packet_t instance, or NULL if invalid
+ */
+ip_packet_t *ip_packet_create(chunk_t packet);
+
+#endif /** IP_PACKET_H_ @}*/
diff --git a/src/libipsec/ipsec.c b/src/libipsec/ipsec.c
new file mode 100644
index 000000000..50d9163ea
--- /dev/null
+++ b/src/libipsec/ipsec.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ipsec.h"
+
+#include <debug.h>
+
+typedef struct private_ipsec_t private_ipsec_t;
+
+/**
+ * Private additions to ipsec_t.
+ */
+struct private_ipsec_t {
+
+ /**
+ * Public members of ipsec_t.
+ */
+ ipsec_t public;
+};
+
+/**
+ * Single instance of ipsec_t.
+ */
+ipsec_t *ipsec;
+
+/**
+ * Described in header.
+ */
+void libipsec_deinit()
+{
+ private_ipsec_t *this = (private_ipsec_t*)ipsec;
+ DESTROY_IF(this->public.processor);
+ DESTROY_IF(this->public.events);
+ DESTROY_IF(this->public.policies);
+ DESTROY_IF(this->public.sas);
+ free(this);
+ ipsec = NULL;
+}
+
+/**
+ * Described in header.
+ */
+bool libipsec_init()
+{
+ private_ipsec_t *this;
+
+ INIT(this);
+ ipsec = &this->public;
+
+ if (lib->integrity &&
+ !lib->integrity->check(lib->integrity, "libipsec", libipsec_init))
+ {
+ DBG1(DBG_LIB, "integrity check of libipsec failed");
+ return FALSE;
+ }
+
+ this->public.sas = ipsec_sa_mgr_create();
+ this->public.policies = ipsec_policy_mgr_create();
+ this->public.events = ipsec_event_relay_create();
+ this->public.processor = ipsec_processor_create();
+ return TRUE;
+}
+
diff --git a/src/libipsec/ipsec.h b/src/libipsec/ipsec.h
new file mode 100644
index 000000000..7ee49432a
--- /dev/null
+++ b/src/libipsec/ipsec.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup libipsec libipsec
+ *
+ * @addtogroup libipsec
+ * @{
+ */
+
+#ifndef IPSEC_H_
+#define IPSEC_H_
+
+#include "ipsec_sa_mgr.h"
+#include "ipsec_policy_mgr.h"
+#include "ipsec_event_relay.h"
+#include "ipsec_processor.h"
+
+#include <library.h>
+
+typedef struct ipsec_t ipsec_t;
+
+/**
+ * User space IPsec implementation.
+ */
+struct ipsec_t {
+
+ /**
+ * IPsec SA manager instance
+ */
+ ipsec_sa_mgr_t *sas;
+
+ /**
+ * IPsec policy manager instance
+ */
+ ipsec_policy_mgr_t *policies;
+
+ /**
+ * Event relay instance
+ */
+ ipsec_event_relay_t *events;
+
+ /**
+ * IPsec processor instance
+ */
+ ipsec_processor_t *processor;
+
+};
+
+/**
+ * The single instance of ipsec_t.
+ *
+ * Set between calls to libipsec_init() and libipsec_deinit() calls.
+ */
+extern ipsec_t *ipsec;
+
+/**
+ * Initialize libipsec.
+ *
+ * @return FALSE if integrity check failed
+ */
+bool libipsec_init();
+
+/**
+ * Deinitialize libipsec.
+ */
+void libipsec_deinit();
+
+#endif /** IPSEC_H_ @}*/
diff --git a/src/libipsec/ipsec_event_listener.h b/src/libipsec/ipsec_event_listener.h
new file mode 100644
index 000000000..c5c39b0f1
--- /dev/null
+++ b/src/libipsec/ipsec_event_listener.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_event_listener ipsec_event_listener
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_EVENT_LISTENER_H_
+#define IPSEC_EVENT_LISTENER_H_
+
+typedef struct ipsec_event_listener_t ipsec_event_listener_t;
+
+#include <library.h>
+
+/**
+ * Listener interface for IPsec events
+ *
+ * All methods are optional.
+ */
+struct ipsec_event_listener_t {
+
+ /**
+ * Called when the lifetime of an IPsec SA expired
+ *
+ * @param reqid reqid of the expired SA
+ * @param protocol protocol of the expired SA
+ * @param spi spi of the expired SA
+ * @param hard TRUE if this is a hard expire, FALSE otherwise
+ */
+ void (*expire)(u_int32_t reqid, u_int8_t protocol, u_int32_t spi,
+ bool hard);
+
+};
+
+#endif /** IPSEC_EVENT_LISTENER_H_ @}*/
diff --git a/src/libipsec/ipsec_event_relay.c b/src/libipsec/ipsec_event_relay.c
new file mode 100644
index 000000000..34222258c
--- /dev/null
+++ b/src/libipsec/ipsec_event_relay.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ipsec_event_relay.h"
+
+#include <library.h>
+#include <debug.h>
+#include <threading/rwlock.h>
+#include <utils/linked_list.h>
+#include <utils/blocking_queue.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_ipsec_event_relay_t private_ipsec_event_relay_t;
+
+/**
+ * Private additions to ipsec_event_relay_t.
+ */
+struct private_ipsec_event_relay_t {
+
+ /**
+ * Public members
+ */
+ ipsec_event_relay_t public;
+
+ /**
+ * Registered listeners
+ */
+ linked_list_t *listeners;
+
+ /**
+ * Lock to safely access the list of listeners
+ */
+ rwlock_t *lock;
+
+ /**
+ * Blocking queue for events
+ */
+ blocking_queue_t *queue;
+};
+
+/**
+ * Helper struct used to manage events in a queue
+ */
+typedef struct {
+
+ /**
+ * Type of the event
+ */
+ enum {
+ IPSEC_EVENT_EXPIRE,
+ } type;
+
+ /**
+ * Reqid of the SA, if any
+ */
+ u_int32_t reqid;
+
+ /**
+ * SPI of the SA, if any
+ */
+ u_int32_t spi;
+
+ /**
+ * Additional data for specific event types
+ */
+ union {
+
+ struct {
+ /** Protocol of the SA */
+ u_int8_t protocol;
+ /** TRUE in case of a hard expire */
+ bool hard;
+ } expire;
+
+ } data;
+
+} ipsec_event_t;
+
+/**
+ * Dequeue events and relay them to listeners
+ */
+static job_requeue_t handle_events(private_ipsec_event_relay_t *this)
+{
+ enumerator_t *enumerator;
+ ipsec_event_listener_t *current;
+ ipsec_event_t *event;
+
+ event = this->queue->dequeue(this->queue);
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->listeners->create_enumerator(this->listeners);
+ while (enumerator->enumerate(enumerator, (void**)&current))
+ {
+ switch (event->type)
+ {
+ case IPSEC_EVENT_EXPIRE:
+ if (current->expire)
+ {
+ current->expire(event->reqid, event->data.expire.protocol,
+ event->spi, event->data.expire.hard);
+ }
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return JOB_REQUEUE_DIRECT;
+}
+
+METHOD(ipsec_event_relay_t, expire, void,
+ private_ipsec_event_relay_t *this, u_int32_t reqid, u_int8_t protocol,
+ u_int32_t spi, bool hard)
+{
+ ipsec_event_t *event;
+
+ INIT(event,
+ .type = IPSEC_EVENT_EXPIRE,
+ .reqid = reqid,
+ .spi = spi,
+ .data = {
+ .expire = {
+ .protocol = protocol,
+ .hard = hard,
+ },
+ },
+ );
+ this->queue->enqueue(this->queue, event);
+}
+
+METHOD(ipsec_event_relay_t, register_listener, void,
+ private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener)
+{
+ this->lock->write_lock(this->lock);
+ this->listeners->insert_last(this->listeners, listener);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_event_relay_t, unregister_listener, void,
+ private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener)
+{
+ this->lock->write_lock(this->lock);
+ this->listeners->remove(this->listeners, listener, NULL);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_event_relay_t, destroy, void,
+ private_ipsec_event_relay_t *this)
+{
+ this->queue->destroy_function(this->queue, free);
+ this->listeners->destroy(this->listeners);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+ipsec_event_relay_t *ipsec_event_relay_create()
+{
+ private_ipsec_event_relay_t *this;
+
+ INIT(this,
+ .public = {
+ .expire = _expire,
+ .register_listener = _register_listener,
+ .unregister_listener = _unregister_listener,
+ .destroy = _destroy,
+ },
+ .listeners = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .queue = blocking_queue_create(),
+ );
+
+ lib->processor->queue_job(lib->processor,
+ (job_t*)callback_job_create((callback_job_cb_t)handle_events, this,
+ NULL, (callback_job_cancel_t)return_false));
+
+ return &this->public;
+}
diff --git a/src/libipsec/ipsec_event_relay.h b/src/libipsec/ipsec_event_relay.h
new file mode 100644
index 000000000..c6935d546
--- /dev/null
+++ b/src/libipsec/ipsec_event_relay.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_event_relay ipsec_event_relay
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_EVENT_RELAY_H_
+#define IPSEC_EVENT_RELAY_H_
+
+#include "ipsec_event_listener.h"
+
+#include <library.h>
+
+typedef struct ipsec_event_relay_t ipsec_event_relay_t;
+
+/**
+ * Event relay manager.
+ *
+ * Used to notify upper layers about changes
+ */
+struct ipsec_event_relay_t {
+
+ /**
+ * Raise an expire event.
+ *
+ * @param reqid reqid of the expired IPsec SA
+ * @param protocol protocol (e.g ESP) of the expired SA
+ * @param spi SPI of the expired SA
+ * @param hard TRUE for a hard expire, FALSE otherwise
+ */
+ void (*expire)(ipsec_event_relay_t *this, u_int32_t reqid,
+ u_int8_t protocol, u_int32_t spi, bool hard);
+
+ /**
+ * Register a listener to events raised by this manager
+ *
+ * @param listener the listener to register
+ */
+ void (*register_listener)(ipsec_event_relay_t *this,
+ ipsec_event_listener_t *listener);
+
+ /**
+ * Unregister a listener
+ *
+ * @param listener the listener to unregister
+ */
+ void (*unregister_listener)(ipsec_event_relay_t *this,
+ ipsec_event_listener_t *listener);
+
+ /**
+ * Destroy an ipsec_event_relay_t
+ */
+ void (*destroy)(ipsec_event_relay_t *this);
+
+};
+
+/**
+ * Create an ipsec_event_relay_t instance
+ *
+ * @return IPsec event relay instance
+ */
+ipsec_event_relay_t *ipsec_event_relay_create();
+
+#endif /** IPSEC_EVENT_RELAY_H_ @}*/
diff --git a/src/libipsec/ipsec_policy.c b/src/libipsec/ipsec_policy.c
new file mode 100644
index 000000000..af8ea9f9d
--- /dev/null
+++ b/src/libipsec/ipsec_policy.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ipsec_policy.h"
+
+#include <debug.h>
+
+typedef struct private_ipsec_policy_t private_ipsec_policy_t;
+
+/**
+ * Private additions to ipsec_policy_t.
+ */
+struct private_ipsec_policy_t {
+
+ /**
+ * Public members
+ */
+ ipsec_policy_t public;
+
+ /**
+ * SA source address
+ */
+ host_t *src;
+
+ /**
+ * SA destination address
+ */
+ host_t *dst;
+
+ /**
+ * Source traffic selector
+ */
+ traffic_selector_t *src_ts;
+
+ /**
+ * Destination traffic selector
+ */
+ traffic_selector_t *dst_ts;
+
+ /**
+ * If any of the two TS has a protocol selector we cache it here
+ */
+ u_int8_t protocol;
+
+ /**
+ * Traffic direction
+ */
+ policy_dir_t direction;
+
+ /**
+ * Policy type
+ */
+ policy_type_t type;
+
+ /**
+ * SA configuration
+ */
+ ipsec_sa_cfg_t sa;
+
+ /**
+ * Mark
+ */
+ mark_t mark;
+
+ /**
+ * Policy priority
+ */
+ policy_priority_t priority;
+
+ /**
+ * Reference counter
+ */
+ refcount_t refcount;
+
+};
+
+METHOD(ipsec_policy_t, match, bool,
+ private_ipsec_policy_t *this, traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ mark_t mark, policy_priority_t priority)
+{
+ return (this->direction == direction &&
+ this->priority == priority &&
+ this->sa.reqid == reqid &&
+ memeq(&this->mark, &mark, sizeof(mark_t)) &&
+ this->src_ts->equals(this->src_ts, src_ts) &&
+ this->dst_ts->equals(this->dst_ts, dst_ts));
+}
+
+METHOD(ipsec_policy_t, match_packet, bool,
+ private_ipsec_policy_t *this, ip_packet_t *packet)
+{
+ u_int8_t proto = packet->get_next_header(packet);
+ host_t *src = packet->get_source(packet),
+ *dst = packet->get_destination(packet);
+
+ return (!this->protocol || this->protocol == proto) &&
+ this->src_ts->includes(this->src_ts, src) &&
+ this->dst_ts->includes(this->dst_ts, dst);
+}
+
+METHOD(ipsec_policy_t, get_source_ts, traffic_selector_t*,
+ private_ipsec_policy_t *this)
+{
+ return this->src_ts;
+}
+
+METHOD(ipsec_policy_t, get_destination_ts, traffic_selector_t*,
+ private_ipsec_policy_t *this)
+{
+ return this->dst_ts;
+}
+
+METHOD(ipsec_policy_t, get_reqid, u_int32_t,
+ private_ipsec_policy_t *this)
+{
+ return this->sa.reqid;
+}
+
+METHOD(ipsec_policy_t, get_direction, policy_dir_t,
+ private_ipsec_policy_t *this)
+{
+ return this->direction;
+}
+
+METHOD(ipsec_policy_t, get_priority, policy_priority_t,
+ private_ipsec_policy_t *this)
+{
+ return this->priority;
+}
+
+METHOD(ipsec_policy_t, get_type, policy_type_t,
+ private_ipsec_policy_t *this)
+{
+ return this->type;
+}
+
+METHOD(ipsec_policy_t, get_ref, ipsec_policy_t*,
+ private_ipsec_policy_t *this)
+{
+ ref_get(&this->refcount);
+ return &this->public;
+}
+
+METHOD(ipsec_policy_t, destroy, void,
+ private_ipsec_policy_t *this)
+{
+ if (ref_put(&this->refcount))
+ {
+ this->src->destroy(this->src);
+ this->dst->destroy(this->dst);
+ this->src_ts->destroy(this->src_ts);
+ this->dst_ts->destroy(this->dst_ts);
+ free(this);
+ }
+}
+
+/**
+ * Described in header.
+ */
+ipsec_policy_t *ipsec_policy_create(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)
+{
+ private_ipsec_policy_t *this;
+
+ INIT(this,
+ .public = {
+ .match = _match,
+ .match_packet = _match_packet,
+ .get_source_ts = _get_source_ts,
+ .get_destination_ts = _get_destination_ts,
+ .get_direction = _get_direction,
+ .get_priority = _get_priority,
+ .get_reqid = _get_reqid,
+ .get_type = _get_type,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .src = src->clone(src),
+ .dst = dst->clone(dst),
+ .src_ts = src_ts->clone(src_ts),
+ .dst_ts = dst_ts->clone(dst_ts),
+ .protocol = max(src_ts->get_protocol(src_ts),
+ dst_ts->get_protocol(dst_ts)),
+ .direction = direction,
+ .type = type,
+ .sa = *sa,
+ .mark = mark,
+ .priority = priority,
+ .refcount = 1,
+ );
+
+ return &this->public;
+}
diff --git a/src/libipsec/ipsec_policy.h b/src/libipsec/ipsec_policy.h
new file mode 100644
index 000000000..67ad0b0ed
--- /dev/null
+++ b/src/libipsec/ipsec_policy.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_policy ipsec_policy
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_POLICY_H
+#define IPSEC_POLICY_H
+
+#include "ip_packet.h"
+
+#include <library.h>
+#include <utils/host.h>
+#include <ipsec/ipsec_types.h>
+#include <selectors/traffic_selector.h>
+
+typedef struct ipsec_policy_t ipsec_policy_t;
+
+/**
+ * IPsec Policy
+ */
+struct ipsec_policy_t {
+
+ /**
+ * Get the source traffic selector of this policy
+ *
+ * @return the source traffic selector
+ */
+ traffic_selector_t *(*get_source_ts)(ipsec_policy_t *this);
+
+ /**
+ * Get the destination traffic selector of this policy
+ *
+ * @return the destination traffic selector
+ */
+ traffic_selector_t *(*get_destination_ts)(ipsec_policy_t *this);
+
+ /**
+ * Get the direction of this policy
+ *
+ * @return direction
+ */
+ policy_dir_t (*get_direction)(ipsec_policy_t *this);
+
+ /**
+ * Get the priority of this policy
+ *
+ * @return priority
+ */
+ policy_priority_t (*get_priority)(ipsec_policy_t *this);
+
+ /**
+ * Get the type of this policy (e.g. IPsec)
+ *
+ * @return the policy type
+ */
+ policy_type_t (*get_type)(ipsec_policy_t *this);
+
+ /**
+ * Get the reqid associated to this policy
+ *
+ * @return the reqid
+ */
+ u_int32_t (*get_reqid)(ipsec_policy_t *this);
+
+ /**
+ * Get another reference to this policy
+ *
+ * @return additional reference to the policy
+ */
+ ipsec_policy_t *(*get_ref)(ipsec_policy_t *this);
+
+ /**
+ * Check if this policy matches all given parameters
+ *
+ * @param src_ts source traffic selector
+ * @param dst_ts destination traffic selector
+ * @param direction traffic direction
+ * @param reqid reqid of the policy
+ * @param mark mark for this policy
+ * @param prioirty policy priority
+ * @return TRUE if policy matches all parameters
+ */
+ bool (*match)(ipsec_policy_t *this, traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts, policy_dir_t direction,
+ u_int32_t reqid, mark_t mark, policy_priority_t priority);
+
+ /**
+ * Check if this policy matches the given IP packet
+ *
+ * @param packet IP packet
+ * @return TRUE if policy matches the packet
+ */
+ bool (*match_packet)(ipsec_policy_t *this, ip_packet_t *packet);
+
+ /**
+ * Destroy an ipsec_policy_t
+ */
+ void (*destroy)(ipsec_policy_t *this);
+
+};
+
+/**
+ * Create an ipsec_policy_t instance
+ *
+ * @param src source address of SA
+ * @param dst dest address of SA
+ * @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 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 priority priority of this policy
+ * @return ipsec policy instance
+ */
+ipsec_policy_t *ipsec_policy_create(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);
+
+#endif /** IPSEC_POLICY_H @}*/
diff --git a/src/libipsec/ipsec_policy_mgr.c b/src/libipsec/ipsec_policy_mgr.c
new file mode 100644
index 000000000..41ba792c3
--- /dev/null
+++ b/src/libipsec/ipsec_policy_mgr.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ipsec_policy_mgr.h"
+
+#include <debug.h>
+#include <threading/rwlock.h>
+#include <utils/linked_list.h>
+
+/** Base priority for installed policies */
+#define PRIO_BASE 512
+
+typedef struct private_ipsec_policy_mgr_t private_ipsec_policy_mgr_t;
+
+/**
+ * Private additions to ipsec_policy_mgr_t.
+ */
+struct private_ipsec_policy_mgr_t {
+
+ /**
+ * Public members of ipsec_policy_mgr_t.
+ */
+ ipsec_policy_mgr_t public;
+
+ /**
+ * Installed policies (ipsec_policy_entry_t*)
+ */
+ linked_list_t *policies;
+
+ /**
+ * Lock to safely access the list of policies
+ */
+ rwlock_t *lock;
+
+};
+
+/**
+ * Helper struct to store policies in a list sorted by the same pseudo-priority
+ * used by the NETLINK kernel interface.
+ */
+typedef struct {
+
+ /**
+ * Priority used to sort policies
+ */
+ u_int32_t priority;
+
+ /**
+ * The policy
+ */
+ ipsec_policy_t *policy;
+
+} ipsec_policy_entry_t;
+
+/**
+ * Calculate the pseudo-priority to sort policies. This is the same algorithm
+ * used by the NETLINK kernel interface (i.e. high priority -> low value).
+ */
+static u_int32_t calculate_priority(policy_priority_t policy_priority,
+ traffic_selector_t *src,
+ traffic_selector_t *dst)
+{
+ u_int32_t priority = PRIO_BASE;
+ u_int16_t port;
+ u_int8_t mask, proto;
+ host_t *net;
+
+ switch (policy_priority)
+ {
+ 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 */
+ src->to_subnet(src, &net, &mask);
+ priority -= mask;
+ proto = src->get_protocol(src);
+ port = net->get_port(net);
+ net->destroy(net);
+
+ dst->to_subnet(dst, &net, &mask);
+ priority -= mask;
+ proto = max(proto, dst->get_protocol(dst));
+ port = max(port, net->get_port(net));
+ net->destroy(net);
+
+ priority <<= 2; /* make some room for the two flags */
+ priority += port ? 0 : 2;
+ priority += proto ? 0 : 1;
+ return priority;
+}
+
+/**
+ * Create a policy entry
+ */
+static ipsec_policy_entry_t *policy_entry_create(ipsec_policy_t *policy)
+{
+ ipsec_policy_entry_t *this;
+
+ INIT(this,
+ .policy = policy,
+ .priority = calculate_priority(policy->get_priority(policy),
+ policy->get_source_ts(policy),
+ policy->get_destination_ts(policy)),
+ );
+ return this;
+}
+
+/**
+ * Destroy a policy entry
+ */
+static void policy_entry_destroy(ipsec_policy_entry_t *this)
+{
+ this->policy->destroy(this->policy);
+ free(this);
+}
+
+METHOD(ipsec_policy_mgr_t, add_policy, status_t,
+ private_ipsec_policy_mgr_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)
+{
+ enumerator_t *enumerator;
+ ipsec_policy_entry_t *entry, *current;
+ ipsec_policy_t *policy;
+
+ if (type != POLICY_IPSEC || direction == POLICY_FWD)
+ { /* we ignore these policies as we currently have no use for them */
+ return SUCCESS;
+ }
+
+ DBG2(DBG_ESP, "adding policy %R === %R %N", src_ts, dst_ts,
+ policy_dir_names, direction);
+
+ policy = ipsec_policy_create(src, dst, src_ts, dst_ts, direction, type, sa,
+ mark, priority);
+ entry = policy_entry_create(policy);
+
+ this->lock->write_lock(this->lock);
+ enumerator = this->policies->create_enumerator(this->policies);
+ while (enumerator->enumerate(enumerator, (void**)&current))
+ {
+ if (current->priority >= entry->priority)
+ {
+ break;
+ }
+ }
+ this->policies->insert_before(this->policies, enumerator, entry);
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return SUCCESS;
+}
+
+METHOD(ipsec_policy_mgr_t, del_policy, status_t,
+ private_ipsec_policy_mgr_t *this, traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ mark_t mark, policy_priority_t policy_priority)
+{
+ enumerator_t *enumerator;
+ ipsec_policy_entry_t *current, *found = NULL;
+ u_int32_t priority;
+
+ if (direction == POLICY_FWD)
+ { /* we ignore these policies as we currently have no use for them */
+ return SUCCESS;
+ }
+ DBG2(DBG_ESP, "deleting policy %R === %R %N", src_ts, dst_ts,
+ policy_dir_names, direction);
+
+ priority = calculate_priority(policy_priority, src_ts, dst_ts);
+
+ this->lock->write_lock(this->lock);
+ enumerator = this->policies->create_enumerator(this->policies);
+ while (enumerator->enumerate(enumerator, (void**)&current))
+ {
+ if (current->priority == priority &&
+ current->policy->match(current->policy, src_ts, dst_ts, direction,
+ reqid, mark, policy_priority))
+ {
+ this->policies->remove_at(this->policies, enumerator);
+ found = current;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ if (found)
+ {
+ policy_entry_destroy(found);
+ return SUCCESS;
+ }
+ return FAILED;
+}
+
+METHOD(ipsec_policy_mgr_t, flush_policies, status_t,
+ private_ipsec_policy_mgr_t *this)
+{
+ ipsec_policy_entry_t *entry;
+
+ DBG2(DBG_ESP, "flushing policies");
+
+ this->lock->write_lock(this->lock);
+ while (this->policies->remove_last(this->policies,
+ (void**)&entry) == SUCCESS)
+ {
+ policy_entry_destroy(entry);
+ }
+ this->lock->unlock(this->lock);
+ return SUCCESS;
+}
+
+METHOD(ipsec_policy_mgr_t, find_by_packet, ipsec_policy_t*,
+ private_ipsec_policy_mgr_t *this, ip_packet_t *packet, bool inbound)
+{
+ enumerator_t *enumerator;
+ ipsec_policy_entry_t *current;
+ ipsec_policy_t *found = NULL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->policies->create_enumerator(this->policies);
+ while (enumerator->enumerate(enumerator, (void**)&current))
+ {
+ ipsec_policy_t *policy = current->policy;
+
+ if ((inbound == (policy->get_direction(policy) == POLICY_IN)) &&
+ policy->match_packet(policy, packet))
+ {
+ found = policy->get_ref(policy);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return found;
+}
+
+METHOD(ipsec_policy_mgr_t, destroy, void,
+ private_ipsec_policy_mgr_t *this)
+{
+ flush_policies(this);
+ this->policies->destroy(this->policies);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+ipsec_policy_mgr_t *ipsec_policy_mgr_create()
+{
+ private_ipsec_policy_mgr_t *this;
+
+ INIT(this,
+ .public = {
+ .add_policy = _add_policy,
+ .del_policy = _del_policy,
+ .flush_policies = _flush_policies,
+ .find_by_packet = _find_by_packet,
+ .destroy = _destroy,
+ },
+ .policies = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/libipsec/ipsec_policy_mgr.h b/src/libipsec/ipsec_policy_mgr.h
new file mode 100644
index 000000000..d3ee1074f
--- /dev/null
+++ b/src/libipsec/ipsec_policy_mgr.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_policy_mgr ipsec_policy_mgr
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_POLICY_MGR_H_
+#define IPSEC_POLICY_MGR_H_
+
+#include "ipsec_policy.h"
+#include "ip_packet.h"
+
+#include <library.h>
+#include <utils/host.h>
+#include <utils/linked_list.h>
+#include <ipsec/ipsec_types.h>
+#include <selectors/traffic_selector.h>
+
+typedef struct ipsec_policy_mgr_t ipsec_policy_mgr_t;
+
+/**
+ * IPsec policy manager
+ *
+ * The first methods are modeled after those in kernel_ipsec_t.
+ *
+ * @note Only policies of type POLICY_IPSEC are currently used, also policies
+ * with direction POLICY_FWD are ignored. Any packets that do not match an
+ * installed policy will be dropped.
+ */
+struct ipsec_policy_mgr_t {
+
+ /**
+ * Add a policy
+ *
+ * A policy is always associated to an SA. Traffic which matches a
+ * policy is handled by the SA with the same reqid.
+ *
+ * @param src source address of SA
+ * @param dst dest address of SA
+ * @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 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 priority priority of this policy
+ * @return SUCCESS if operation completed
+ */
+ status_t (*add_policy)(ipsec_policy_mgr_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);
+
+ /**
+ * Remove a policy
+ *
+ * @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 priority priority of the policy
+ * @return SUCCESS if operation completed
+ */
+ status_t (*del_policy)(ipsec_policy_mgr_t *this,
+ traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts,
+ policy_dir_t direction, u_int32_t reqid, mark_t mark,
+ policy_priority_t priority);
+
+ /**
+ * Flush all policies
+ *
+ * @return SUCCESS if operation completed
+ */
+ status_t (*flush_policies)(ipsec_policy_mgr_t *this);
+
+ /**
+ * Find the policy that matches the given IP packet best
+ *
+ * @param packet IP packet to match
+ * @param inbound TRUE for an inbound packet
+ * @return reference to the policy, or NULL if none found
+ */
+ ipsec_policy_t *(*find_by_packet)(ipsec_policy_mgr_t *this,
+ ip_packet_t *packet, bool inbound);
+
+ /**
+ * Destroy an ipsec_policy_mgr_t
+ */
+ void (*destroy)(ipsec_policy_mgr_t *this);
+
+};
+
+/**
+ * Create an ipsec_policy_mgr instance
+ *
+ * @return ipsec_policy_mgr
+ */
+ipsec_policy_mgr_t *ipsec_policy_mgr_create();
+
+#endif /** IPSEC_POLICY_MGR_H_ @}*/
diff --git a/src/libipsec/ipsec_processor.c b/src/libipsec/ipsec_processor.c
new file mode 100644
index 000000000..a91d9e074
--- /dev/null
+++ b/src/libipsec/ipsec_processor.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ipsec.h"
+#include "ipsec_processor.h"
+
+#include <debug.h>
+#include <library.h>
+#include <threading/rwlock.h>
+#include <utils/blocking_queue.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_ipsec_processor_t private_ipsec_processor_t;
+
+/**
+ * Private additions to ipsec_processor_t.
+ */
+struct private_ipsec_processor_t {
+
+ /**
+ * Public members
+ */
+ ipsec_processor_t public;
+
+ /**
+ * Queue for inbound packets (esp_packet_t*)
+ */
+ blocking_queue_t *inbound_queue;
+
+ /**
+ * Queue for outbound packets (ip_packet_t*)
+ */
+ blocking_queue_t *outbound_queue;
+
+ /**
+ * Registered inbound callback
+ */
+ struct {
+ ipsec_inbound_cb_t cb;
+ void *data;
+ } inbound;
+
+ /**
+ * Registered outbound callback
+ */
+ struct {
+ ipsec_outbound_cb_t cb;
+ void *data;
+ } outbound;
+
+ /**
+ * Lock used to synchronize access to the callbacks
+ */
+ rwlock_t *lock;
+};
+
+/**
+ * Deliver an inbound IP packet to the registered listener
+ */
+static void deliver_inbound(private_ipsec_processor_t *this,
+ esp_packet_t *packet)
+{
+ this->lock->read_lock(this->lock);
+ if (this->inbound.cb)
+ {
+ this->inbound.cb(this->inbound.data, packet->extract_payload(packet));
+ }
+ else
+ {
+ DBG2(DBG_ESP, "no inbound callback registered, dropping packet");
+ }
+ packet->destroy(packet);
+ this->lock->unlock(this->lock);
+}
+
+/**
+ * Processes inbound packets
+ */
+static job_requeue_t process_inbound(private_ipsec_processor_t *this)
+{
+ esp_packet_t *packet;
+ ipsec_sa_t *sa;
+ u_int8_t next_header;
+ u_int32_t spi;
+
+ packet = (esp_packet_t*)this->inbound_queue->dequeue(this->inbound_queue);
+
+ if (!packet->parse_header(packet, &spi))
+ {
+ packet->destroy(packet);
+ return JOB_REQUEUE_DIRECT;
+ }
+
+ sa = ipsec->sas->checkout_by_spi(ipsec->sas, spi,
+ packet->get_destination(packet));
+ if (!sa)
+ {
+ DBG2(DBG_ESP, "inbound ESP packet does not belong to an installed SA");
+ packet->destroy(packet);
+ return JOB_REQUEUE_DIRECT;
+ }
+
+ if (!sa->is_inbound(sa))
+ {
+ DBG1(DBG_ESP, "error: IPsec SA is not inbound");
+ packet->destroy(packet);
+ ipsec->sas->checkin(ipsec->sas, sa);
+ return JOB_REQUEUE_DIRECT;
+ }
+
+ if (packet->decrypt(packet, sa->get_esp_context(sa)) != SUCCESS)
+ {
+ ipsec->sas->checkin(ipsec->sas, sa);
+ packet->destroy(packet);
+ return JOB_REQUEUE_DIRECT;
+ }
+ ipsec->sas->checkin(ipsec->sas, sa);
+
+ next_header = packet->get_next_header(packet);
+ switch (next_header)
+ {
+ case IPPROTO_IPIP:
+ case IPPROTO_IPV6:
+ {
+ ipsec_policy_t *policy;
+ ip_packet_t *ip_packet;
+
+ ip_packet = packet->get_payload(packet);
+ policy = ipsec->policies->find_by_packet(ipsec->policies,
+ ip_packet, TRUE);
+ if (policy)
+ { /* TODO-IPSEC: update policy/sa stats? */
+ deliver_inbound(this, packet);
+ policy->destroy(policy);
+ break;
+ }
+ DBG1(DBG_ESP, "discarding inbound IP packet due to policy");
+ /* no matching policy found, fall-through */
+ }
+ case IPPROTO_NONE:
+ /* discard dummy packets */
+ /* fall-through */
+ default:
+ packet->destroy(packet);
+ break;
+ }
+ return JOB_REQUEUE_DIRECT;
+}
+
+/**
+ * Send an ESP packet using the registered outbound callback
+ */
+static void send_outbound(private_ipsec_processor_t *this,
+ esp_packet_t *packet)
+{
+ this->lock->read_lock(this->lock);
+ if (this->outbound.cb)
+ {
+ this->outbound.cb(this->outbound.data, packet);
+ }
+ else
+ {
+ DBG2(DBG_ESP, "no outbound callback registered, dropping packet");
+ packet->destroy(packet);
+ }
+ this->lock->unlock(this->lock);
+}
+
+/**
+ * Processes outbound packets
+ */
+static job_requeue_t process_outbound(private_ipsec_processor_t *this)
+{
+ ipsec_policy_t *policy;
+ esp_packet_t *esp_packet;
+ ip_packet_t *packet;
+ ipsec_sa_t *sa;
+ host_t *src, *dst;
+
+ packet = (ip_packet_t*)this->outbound_queue->dequeue(this->outbound_queue);
+
+ policy = ipsec->policies->find_by_packet(ipsec->policies, packet, FALSE);
+ if (!policy)
+ {
+ DBG1(DBG_ESP, "no matching outbound IPsec policy for %H == %H",
+ packet->get_source(packet), packet->get_destination(packet));
+ packet->destroy(packet);
+ return JOB_REQUEUE_DIRECT;
+ }
+
+ sa = ipsec->sas->checkout_by_reqid(ipsec->sas, policy->get_reqid(policy),
+ FALSE);
+ if (!sa)
+ { /* TODO-IPSEC: send an acquire to uppper layer */
+ DBG1(DBG_ESP, "could not find an outbound IPsec SA for reqid {%u}, "
+ "dropping packet", policy->get_reqid(policy));
+ packet->destroy(packet);
+ policy->destroy(policy);
+ return JOB_REQUEUE_DIRECT;
+ }
+ src = sa->get_source(sa);
+ dst = sa->get_destination(sa);
+ esp_packet = esp_packet_create_from_payload(src->clone(src),
+ dst->clone(dst), packet);
+ if (esp_packet->encrypt(esp_packet, sa->get_esp_context(sa),
+ sa->get_spi(sa)) != SUCCESS)
+ {
+ ipsec->sas->checkin(ipsec->sas, sa);
+ esp_packet->destroy(esp_packet);
+ policy->destroy(policy);
+ return JOB_REQUEUE_DIRECT;
+ }
+ /* TODO-IPSEC: update policy/sa counters? */
+ ipsec->sas->checkin(ipsec->sas, sa);
+ policy->destroy(policy);
+ send_outbound(this, esp_packet);
+ return JOB_REQUEUE_DIRECT;
+}
+
+METHOD(ipsec_processor_t, queue_inbound, void,
+ private_ipsec_processor_t *this, esp_packet_t *packet)
+{
+ this->inbound_queue->enqueue(this->inbound_queue, packet);
+}
+
+METHOD(ipsec_processor_t, queue_outbound, void,
+ private_ipsec_processor_t *this, ip_packet_t *packet)
+{
+ this->outbound_queue->enqueue(this->outbound_queue, packet);
+}
+
+METHOD(ipsec_processor_t, register_inbound, void,
+ private_ipsec_processor_t *this, ipsec_inbound_cb_t cb, void *data)
+{
+ this->lock->write_lock(this->lock);
+ this->inbound.cb = cb;
+ this->inbound.data = data;
+ this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_processor_t, unregister_inbound, void,
+ private_ipsec_processor_t *this, ipsec_inbound_cb_t cb)
+{
+ this->lock->write_lock(this->lock);
+ if (this->inbound.cb == cb)
+ {
+ this->inbound.cb = NULL;
+ }
+ this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_processor_t, register_outbound, void,
+ private_ipsec_processor_t *this, ipsec_outbound_cb_t cb, void *data)
+{
+ this->lock->write_lock(this->lock);
+ this->outbound.cb = cb;
+ this->outbound.data = data;
+ this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_processor_t, unregister_outbound, void,
+ private_ipsec_processor_t *this, ipsec_outbound_cb_t cb)
+{
+ this->lock->write_lock(this->lock);
+ if (this->outbound.cb == cb)
+ {
+ this->outbound.cb = NULL;
+ }
+ this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_processor_t, destroy, void,
+ private_ipsec_processor_t *this)
+{
+ this->inbound_queue->destroy_offset(this->inbound_queue,
+ offsetof(esp_packet_t, destroy));
+ this->outbound_queue->destroy_offset(this->outbound_queue,
+ offsetof(ip_packet_t, destroy));
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+ipsec_processor_t *ipsec_processor_create()
+{
+ private_ipsec_processor_t *this;
+
+ INIT(this,
+ .public = {
+ .queue_inbound = _queue_inbound,
+ .queue_outbound = _queue_outbound,
+ .register_inbound = _register_inbound,
+ .unregister_inbound = _unregister_inbound,
+ .register_outbound = _register_outbound,
+ .unregister_outbound = _unregister_outbound,
+ .destroy = _destroy,
+ },
+ .inbound_queue = blocking_queue_create(),
+ .outbound_queue = blocking_queue_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ lib->processor->queue_job(lib->processor,
+ (job_t*)callback_job_create((callback_job_cb_t)process_inbound, this,
+ NULL, (callback_job_cancel_t)return_false));
+ lib->processor->queue_job(lib->processor,
+ (job_t*)callback_job_create((callback_job_cb_t)process_outbound, this,
+ NULL, (callback_job_cancel_t)return_false));
+ return &this->public;
+}
diff --git a/src/libipsec/ipsec_processor.h b/src/libipsec/ipsec_processor.h
new file mode 100644
index 000000000..0a409828b
--- /dev/null
+++ b/src/libipsec/ipsec_processor.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_processor ipsec_processor
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_PROCESSOR_H_
+#define IPSEC_PROCESSOR_H_
+
+#include "ip_packet.h"
+#include "esp_packet.h"
+
+typedef struct ipsec_processor_t ipsec_processor_t;
+
+/**
+ * Callback called to deliver an inbound plaintext packet.
+ *
+ * @param data data supplied during registration of the callback
+ * @param packet plaintext IP packet to deliver
+ */
+typedef void (*ipsec_inbound_cb_t)(void *data, ip_packet_t *packet);
+
+/**
+ * Callback called to send an ESP packet.
+ *
+ * @note The ESP packet currently comes without IP header (and without UDP
+ * header in case of UDP encapsulation)
+ *
+ * @param data data supplied during registration of the callback
+ * @param packet ESP packet to send
+ */
+typedef void (*ipsec_outbound_cb_t)(void *data, esp_packet_t *packet);
+
+/**
+ * IPsec processor
+ */
+struct ipsec_processor_t {
+
+ /**
+ * Queue an inbound ESP packet for processing.
+ *
+ * @param packet the ESP packet to process
+ */
+ void (*queue_inbound)(ipsec_processor_t *this, esp_packet_t *packet);
+
+ /**
+ * Queue an outbound plaintext IP packet for processing.
+ *
+ * @param packet the plaintext IP packet
+ */
+ void (*queue_outbound)(ipsec_processor_t *this, ip_packet_t *packet);
+
+ /**
+ * Register the callback used to deliver inbound plaintext packets.
+ *
+ * @param cb the inbound callback function
+ * @param data optional data provided to callback
+ */
+ void (*register_inbound)(ipsec_processor_t *this, ipsec_inbound_cb_t cb,
+ void *data);
+
+ /**
+ * Unregister a previously registered inbound callback.
+ *
+ * @param cb previously registered callback function
+ */
+ void (*unregister_inbound)(ipsec_processor_t *this,
+ ipsec_inbound_cb_t cb);
+
+ /**
+ * Register the callback used to send outbound ESP packets.
+ *
+ * @param cb the outbound callback function
+ * @param data optional data provided to callback
+ */
+ void (*register_outbound)(ipsec_processor_t *this, ipsec_outbound_cb_t cb,
+ void *data);
+
+ /**
+ * Unregister a previously registered outbound callback.
+ *
+ * @param cb previously registered callback function
+ */
+ void (*unregister_outbound)(ipsec_processor_t *this,
+ ipsec_outbound_cb_t cb);
+
+ /**
+ * Destroy an ipsec_processor_t.
+ */
+ void (*destroy)(ipsec_processor_t *this);
+
+};
+
+/**
+ * Create an ipsec_processor_t instance
+ *
+ * @return IPsec processor instance
+ */
+ipsec_processor_t *ipsec_processor_create();
+
+#endif /** IPSEC_PROCESSOR_H_ @}*/
diff --git a/src/libipsec/ipsec_sa.c b/src/libipsec/ipsec_sa.c
new file mode 100644
index 000000000..cccd16404
--- /dev/null
+++ b/src/libipsec/ipsec_sa.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ipsec_sa.h"
+
+#include <library.h>
+#include <debug.h>
+
+typedef struct private_ipsec_sa_t private_ipsec_sa_t;
+
+/**
+ * Private additions to ipsec_sa_t.
+ */
+struct private_ipsec_sa_t {
+
+ /**
+ * Public members
+ */
+ ipsec_sa_t public;
+
+ /**
+ * SPI of this SA
+ */
+ u_int32_t spi;
+
+ /**
+ * Source address
+ */
+ host_t *src;
+
+ /**
+ * Destination address
+ */
+ host_t *dst;
+
+ /**
+ * Protocol
+ */
+ u_int8_t protocol;
+
+ /**
+ * Reqid of this SA
+ */
+ u_int32_t reqid;
+
+ /**
+ * Lifetime configuration
+ */
+ lifetime_cfg_t lifetime;
+
+ /**
+ * IPsec mode
+ */
+ ipsec_mode_t mode;
+
+ /**
+ * TRUE if extended sequence numbers are used
+ */
+ bool esn;
+
+ /**
+ * TRUE if this is an inbound SA
+ */
+ bool inbound;
+
+ /**
+ * ESP context
+ */
+ esp_context_t *esp_context;
+};
+
+METHOD(ipsec_sa_t, get_source, host_t*,
+ private_ipsec_sa_t *this)
+{
+ return this->src;
+}
+
+METHOD(ipsec_sa_t, get_destination, host_t*,
+ private_ipsec_sa_t *this)
+{
+ return this->dst;
+}
+
+METHOD(ipsec_sa_t, get_spi, u_int32_t,
+ private_ipsec_sa_t *this)
+{
+ return this->spi;
+}
+
+METHOD(ipsec_sa_t, get_reqid, u_int32_t,
+ private_ipsec_sa_t *this)
+{
+ return this->reqid;
+}
+
+METHOD(ipsec_sa_t, get_protocol, u_int8_t,
+ private_ipsec_sa_t *this)
+{
+ return this->protocol;
+}
+
+METHOD(ipsec_sa_t, get_lifetime, lifetime_cfg_t*,
+ private_ipsec_sa_t *this)
+{
+ return &this->lifetime;
+}
+
+METHOD(ipsec_sa_t, is_inbound, bool,
+ private_ipsec_sa_t *this)
+{
+ return this->inbound;
+}
+
+METHOD(ipsec_sa_t, get_esp_context, esp_context_t*,
+ private_ipsec_sa_t *this)
+{
+ return this->esp_context;
+}
+
+METHOD(ipsec_sa_t, match_by_spi_dst, bool,
+ private_ipsec_sa_t *this, u_int32_t spi, host_t *dst)
+{
+ return this->spi == spi && this->dst->ip_equals(this->dst, dst);
+}
+
+METHOD(ipsec_sa_t, match_by_spi_src_dst, bool,
+ private_ipsec_sa_t *this, u_int32_t spi, host_t *src, host_t *dst)
+{
+ return this->spi == spi && this->src->ip_equals(this->src, src) &&
+ this->dst->ip_equals(this->dst, dst);
+}
+
+METHOD(ipsec_sa_t, match_by_reqid, bool,
+ private_ipsec_sa_t *this, u_int32_t reqid, bool inbound)
+{
+ return this->reqid == reqid && this->inbound == inbound;
+}
+
+METHOD(ipsec_sa_t, destroy, void,
+ private_ipsec_sa_t *this)
+{
+ this->src->destroy(this->src);
+ this->dst->destroy(this->dst);
+ DESTROY_IF(this->esp_context);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst,
+ u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc,
+ lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
+ u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
+ u_int16_t ipcomp, u_int16_t cpi, bool encap, bool esn, bool inbound,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+{
+ private_ipsec_sa_t *this;
+
+ if (protocol != IPPROTO_ESP)
+ {
+ DBG1(DBG_ESP, " IPsec SA: protocol not supported");
+ return NULL;
+ }
+ if (!encap)
+ {
+ DBG1(DBG_ESP, " IPsec SA: only UDP encapsulation is supported");
+ return NULL;
+ }
+ if (esn)
+ {
+ DBG1(DBG_ESP, " IPsec SA: ESN not supported");
+ return NULL;
+ }
+ if (ipcomp != IPCOMP_NONE)
+ {
+ DBG1(DBG_ESP, " IPsec SA: compression not supported");
+ return NULL;
+ }
+ if (mode != MODE_TUNNEL)
+ {
+ DBG1(DBG_ESP, " IPsec SA: unsupported mode");
+ return NULL;
+ }
+
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ .get_source = _get_source,
+ .get_destination = _get_destination,
+ .get_spi = _get_spi,
+ .get_reqid = _get_reqid,
+ .get_protocol = _get_protocol,
+ .get_lifetime = _get_lifetime,
+ .is_inbound = _is_inbound,
+ .match_by_spi_dst = _match_by_spi_dst,
+ .match_by_spi_src_dst = _match_by_spi_src_dst,
+ .match_by_reqid = _match_by_reqid,
+ .get_esp_context = _get_esp_context,
+ },
+ .spi = spi,
+ .src = src->clone(src),
+ .dst = dst->clone(dst),
+ .lifetime = *lifetime,
+ .protocol = protocol,
+ .reqid = reqid,
+ .mode = mode,
+ .esn = esn,
+ .inbound = inbound,
+ );
+
+ this->esp_context = esp_context_create(enc_alg, enc_key, int_alg, int_key,
+ inbound);
+ if (!this->esp_context)
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
diff --git a/src/libipsec/ipsec_sa.h b/src/libipsec/ipsec_sa.h
new file mode 100644
index 000000000..5fd03b6e4
--- /dev/null
+++ b/src/libipsec/ipsec_sa.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_sa ipsec_sa
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_SA_H_
+#define IPSEC_SA_H_
+
+#include "esp_context.h"
+
+#include <library.h>
+#include <utils/host.h>
+#include <selectors/traffic_selector.h>
+#include <ipsec/ipsec_types.h>
+
+typedef struct ipsec_sa_t ipsec_sa_t;
+
+/**
+ * IPsec Security Association (SA)
+ */
+struct ipsec_sa_t {
+
+ /**
+ * Get the source address for this SA
+ *
+ * @return source address of this SA
+ */
+ host_t *(*get_source)(ipsec_sa_t *this);
+
+ /**
+ * Get the destination address for this SA
+ *
+ * @return destination address of this SA
+ */
+ host_t *(*get_destination)(ipsec_sa_t *this);
+
+ /**
+ * Get the SPI for this SA
+ *
+ * @return SPI of this SA
+ */
+ u_int32_t (*get_spi)(ipsec_sa_t *this);
+
+ /**
+ * Get the reqid of this SA
+ *
+ * @return reqid of this SA
+ */
+ u_int32_t (*get_reqid)(ipsec_sa_t *this);
+
+ /**
+ * Get the protocol (e.g. IPPROTO_ESP) of this SA
+ *
+ * @return protocol of this SA
+ */
+ u_int8_t (*get_protocol)(ipsec_sa_t *this);
+
+ /**
+ * Returns whether this SA is inbound or outbound
+ *
+ * @return TRUE if inbound, FALSE if outbound
+ */
+ bool (*is_inbound)(ipsec_sa_t *this);
+
+ /**
+ * Get the lifetime information for this SA
+ * Note that this information is always relative to the time when the
+ * SA was installed (i.e. it is not adjusted over time)
+ *
+ * @return lifetime of this SA
+ */
+ lifetime_cfg_t *(*get_lifetime)(ipsec_sa_t *this);
+
+ /**
+ * Get the ESP context for this SA
+ *
+ * @return ESP context of this SA
+ */
+ esp_context_t *(*get_esp_context)(ipsec_sa_t *this);
+
+ /**
+ * Check if this SA matches all given parameters
+ *
+ * @param spi SPI
+ * @param dst destination address
+ * @return TRUE if this SA matches all parameters, FALSE otherwise
+ */
+ bool (*match_by_spi_dst)(ipsec_sa_t *this, u_int32_t spi, host_t *dst);
+
+ /**
+ * Check if this SA matches all given parameters
+ *
+ * @param spi SPI
+ * @param src source address
+ * @param dst destination address
+ * @return TRUE if this SA matches all parameters, FALSE otherwise
+ */
+ bool (*match_by_spi_src_dst)(ipsec_sa_t *this, u_int32_t spi, host_t *src,
+ host_t *dst);
+
+ /**
+ * Check if this SA matches all given parameters
+ *
+ * @param reqid reqid
+ * @param inbound TRUE for inbound SA, FALSE for outbound
+ * @return TRUE if this SA matches all parameters, FALSE otherwise
+ */
+ bool (*match_by_reqid)(ipsec_sa_t *this, u_int32_t reqid, bool inbound);
+
+ /**
+ * Destroy an ipsec_sa_t
+ */
+ void (*destroy)(ipsec_sa_t *this);
+
+};
+
+/**
+ * Create an ipsec_sa_t instance
+ *
+ * @param spi SPI for this SA
+ * @param src source address for this SA (gets cloned)
+ * @param dst destination address for this SA (gets cloned)
+ * @param protocol protocol for this SA (only ESP is supported)
+ * @param reqid reqid for this SA
+ * @param mark mark for this SA (ignored)
+ * @param tfc Traffic Flow Confidentiality (currently not supported)
+ * @param lifetime lifetime for this SA
+ * @param enc_alg encryption algorithm for this SA
+ * @param enc_key encryption key for this SA
+ * @param int_alg integrity protection algorithm
+ * @param int_key integrity protection key
+ * @param mode mode for this SA (only tunnel mode is supported)
+ * @param ipcomp IPcomp transform (not supported, use IPCOMP_NONE)
+ * @param cpi CPI for IPcomp (ignored)
+ * @param encap enable UDP encapsulation (must be TRUE)
+ * @param esn Extended Sequence Numbers (currently not supported)
+ * @param inbound TRUE if this is an inbound SA, FALSE otherwise
+ * @param src_ts source traffic selector
+ * @param dst_ts destination traffic selector
+ * @return the IPsec SA, or NULL if the creation failed
+ */
+ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst,
+ u_int8_t protocol, u_int32_t reqid, mark_t mark,
+ u_int32_t tfc, lifetime_cfg_t *lifetime,
+ u_int16_t enc_alg, chunk_t enc_key,
+ u_int16_t int_alg, chunk_t int_key,
+ ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
+ bool encap, bool esn, bool inbound,
+ traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts);
+
+#endif /** IPSEC_SA_H_ @}*/
diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c
new file mode 100644
index 000000000..e42c77aa5
--- /dev/null
+++ b/src/libipsec/ipsec_sa_mgr.c
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ipsec.h"
+#include "ipsec_sa_mgr.h"
+
+#include <debug.h>
+#include <library.h>
+#include <processing/jobs/callback_job.h>
+#include <threading/condvar.h>
+#include <threading/mutex.h>
+#include <utils/hashtable.h>
+#include <utils/linked_list.h>
+
+typedef struct private_ipsec_sa_mgr_t private_ipsec_sa_mgr_t;
+
+/**
+ * Private additions to ipsec_sa_mgr_t.
+ */
+struct private_ipsec_sa_mgr_t {
+
+ /**
+ * Public members of ipsec_sa_mgr_t.
+ */
+ ipsec_sa_mgr_t public;
+
+ /**
+ * Installed SAs
+ */
+ linked_list_t *sas;
+
+ /**
+ * SPIs allocated using get_spi()
+ */
+ hashtable_t *allocated_spis;
+
+ /**
+ * Mutex used to synchronize access to the SA manager
+ */
+ mutex_t *mutex;
+
+ /**
+ * RNG used to generate SPIs
+ */
+ rng_t *rng;
+};
+
+/**
+ * Struct to keep track of locked IPsec SAs
+ */
+typedef struct {
+
+ /**
+ * IPsec SA
+ */
+ ipsec_sa_t *sa;
+
+ /**
+ * Set if this SA is currently in use by a thread
+ */
+ bool locked;
+
+ /**
+ * Condvar used by threads to wait for this entry
+ */
+ condvar_t *condvar;
+
+ /**
+ * Number of threads waiting for this entry
+ */
+ u_int waiting_threads;
+
+ /**
+ * Set if this entry is awaiting deletion
+ */
+ bool awaits_deletion;
+
+} ipsec_sa_entry_t;
+
+/**
+ * Helper struct for expiration events
+ */
+typedef struct {
+
+ /**
+ * IPsec SA manager
+ */
+ private_ipsec_sa_mgr_t *manager;
+
+ /**
+ * Entry that expired
+ */
+ ipsec_sa_entry_t *entry;
+
+ /**
+ * 0 if this is a hard expire, otherwise the offset in s (soft->hard)
+ */
+ u_int32_t hard_offset;
+
+} ipsec_sa_expired_t;
+
+/*
+ * Used for the hash table of allocated SPIs
+ */
+static bool spi_equals(u_int32_t *spi, u_int32_t *other_spi)
+{
+ return *spi == *other_spi;
+}
+
+static u_int spi_hash(u_int32_t *spi)
+{
+ return chunk_hash(chunk_from_thing(*spi));
+}
+
+/**
+ * Create an SA entry
+ */
+static ipsec_sa_entry_t *create_entry(ipsec_sa_t *sa)
+{
+ ipsec_sa_entry_t *this;
+
+ INIT(this,
+ .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .sa = sa,
+ );
+ return this;
+}
+
+/**
+ * Destroy an SA entry
+ */
+static void destroy_entry(ipsec_sa_entry_t *entry)
+{
+ entry->condvar->destroy(entry->condvar);
+ entry->sa->destroy(entry->sa);
+ free(entry);
+}
+
+/**
+ * Makes sure an entry is safe to remove
+ * Must be called with this->mutex held.
+ *
+ * @return TRUE if entry can be removed, FALSE if entry is already
+* being removed by another thread
+ */
+static bool wait_remove_entry(private_ipsec_sa_mgr_t *this,
+ ipsec_sa_entry_t *entry)
+{
+ if (entry->awaits_deletion)
+ {
+ /* this will be deleted by another thread already */
+ return FALSE;
+ }
+ entry->awaits_deletion = TRUE;
+ while (entry->locked)
+ {
+ entry->condvar->wait(entry->condvar, this->mutex);
+ }
+ while (entry->waiting_threads > 0)
+ {
+ entry->condvar->broadcast(entry->condvar);
+ entry->condvar->wait(entry->condvar, this->mutex);
+ }
+ return TRUE;
+}
+
+/**
+ * Waits until an is available and then locks it.
+ * Must only be called with this->mutex held
+ */
+static bool wait_for_entry(private_ipsec_sa_mgr_t *this,
+ ipsec_sa_entry_t *entry)
+{
+ while (entry->locked && !entry->awaits_deletion)
+ {
+ entry->waiting_threads++;
+ entry->condvar->wait(entry->condvar, this->mutex);
+ entry->waiting_threads--;
+ }
+ if (entry->awaits_deletion)
+ {
+ /* others may still be waiting, */
+ entry->condvar->signal(entry->condvar);
+ return FALSE;
+ }
+ entry->locked = TRUE;
+ return TRUE;
+}
+
+/**
+ * Flushes all entries
+ * Must be called with this->mutex held.
+ */
+static void flush_entries(private_ipsec_sa_mgr_t *this)
+{
+ ipsec_sa_entry_t *current;
+ enumerator_t *enumerator;
+
+ DBG2(DBG_ESP, "flushing SAD");
+
+ enumerator = this->sas->create_enumerator(this->sas);
+ while (enumerator->enumerate(enumerator, (void**)&current))
+ {
+ if (wait_remove_entry(this, current))
+ {
+ this->sas->remove_at(this->sas, enumerator);
+ destroy_entry(current);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/*
+ * Different match functions to find SAs in the linked list
+ */
+static bool match_entry_by_ptr(ipsec_sa_entry_t *item, ipsec_sa_entry_t *entry)
+{
+ return item == entry;
+}
+
+static bool match_entry_by_sa_ptr(ipsec_sa_entry_t *item, ipsec_sa_t *sa)
+{
+ return item->sa == sa;
+}
+
+static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, u_int32_t spi,
+ bool inbound)
+{
+ return item->sa->get_spi(item->sa) == spi &&
+ item->sa->is_inbound(item->sa) == inbound;
+}
+
+static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, u_int32_t spi,
+ host_t *src, host_t *dst)
+{
+ return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst);
+}
+
+static bool match_entry_by_reqid_inbound(ipsec_sa_entry_t *item,
+ u_int32_t reqid, bool inbound)
+{
+ return item->sa->match_by_reqid(item->sa, reqid, inbound);
+}
+
+static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, u_int32_t spi,
+ host_t *dst)
+{
+ return item->sa->match_by_spi_dst(item->sa, spi, dst);
+}
+
+/**
+ * Remove an entry
+ */
+static bool remove_entry(private_ipsec_sa_mgr_t *this, ipsec_sa_entry_t *entry)
+{
+ ipsec_sa_entry_t *current;
+ enumerator_t *enumerator;
+ bool removed = FALSE;
+
+ enumerator = this->sas->create_enumerator(this->sas);
+ while (enumerator->enumerate(enumerator, (void**)&current))
+ {
+ if (current == entry)
+ {
+ if (wait_remove_entry(this, current))
+ {
+ this->sas->remove_at(this->sas, enumerator);
+ removed = TRUE;
+ }
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return removed;
+}
+
+/**
+ * Callback for expiration events
+ */
+static job_requeue_t sa_expired(ipsec_sa_expired_t *expired)
+{
+ private_ipsec_sa_mgr_t *this = expired->manager;
+
+ this->mutex->lock(this->mutex);
+ if (this->sas->find_first(this->sas, (void*)match_entry_by_ptr,
+ NULL, expired->entry) == SUCCESS)
+ {
+ u_int32_t hard_offset = expired->hard_offset;
+ ipsec_sa_t *sa = expired->entry->sa;
+
+ ipsec->events->expire(ipsec->events, sa->get_reqid(sa),
+ sa->get_protocol(sa), sa->get_spi(sa),
+ hard_offset == 0);
+ if (hard_offset)
+ { /* soft limit reached, schedule hard expire */
+ expired->hard_offset = 0;
+ this->mutex->unlock(this->mutex);
+ return JOB_RESCHEDULE(hard_offset);
+ }
+ /* hard limit reached */
+ if (remove_entry(this, expired->entry))
+ {
+ destroy_entry(expired->entry);
+ }
+ }
+ this->mutex->unlock(this->mutex);
+ return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Schedule a job to handle IPsec SA expiration
+ */
+static void schedule_expiration(private_ipsec_sa_mgr_t *this,
+ ipsec_sa_entry_t *entry)
+{
+ lifetime_cfg_t *lifetime = entry->sa->get_lifetime(entry->sa);
+ ipsec_sa_expired_t *expired;
+ callback_job_t *job;
+ u_int32_t timeout;
+
+ INIT(expired,
+ .manager = this,
+ .entry = entry,
+ );
+
+ /* schedule a rekey first, a hard timeout will be scheduled then, if any */
+ expired->hard_offset = lifetime->time.life - lifetime->time.rekey;
+ timeout = lifetime->time.rekey;
+
+ if (lifetime->time.life <= lifetime->time.rekey ||
+ lifetime->time.rekey == 0)
+ { /* no rekey, schedule hard timeout */
+ expired->hard_offset = 0;
+ timeout = lifetime->time.life;
+ }
+
+ job = callback_job_create((callback_job_cb_t)sa_expired, expired,
+ (callback_job_cleanup_t)free, NULL);
+ lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, timeout);
+}
+
+/**
+ * Remove all allocated SPIs
+ */
+static void flush_allocated_spis(private_ipsec_sa_mgr_t *this)
+{
+ enumerator_t *enumerator;
+ u_int32_t *current;
+
+ DBG2(DBG_ESP, "flushing allocated SPIs");
+ enumerator = this->allocated_spis->create_enumerator(this->allocated_spis);
+ while (enumerator->enumerate(enumerator, NULL, (void**)&current))
+ {
+ this->allocated_spis->remove_at(this->allocated_spis, enumerator);
+ DBG2(DBG_ESP, " removed allocated SPI %.8x", ntohl(*current));
+ free(current);
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Pre-allocate an SPI for an inbound SA
+ */
+static bool allocate_spi(private_ipsec_sa_mgr_t *this, u_int32_t spi)
+{
+ u_int32_t *spi_alloc;
+
+ if (this->allocated_spis->get(this->allocated_spis, &spi) ||
+ this->sas->find_first(this->sas, (void*)match_entry_by_spi_inbound,
+ NULL, spi, TRUE) == SUCCESS)
+ {
+ return FALSE;
+ }
+ spi_alloc = malloc_thing(u_int32_t);
+ *spi_alloc = spi;
+ this->allocated_spis->put(this->allocated_spis, spi_alloc, spi_alloc);
+ return TRUE;
+}
+
+METHOD(ipsec_sa_mgr_t, get_spi, status_t,
+ private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int8_t protocol,
+ u_int32_t reqid, u_int32_t *spi)
+{
+ u_int32_t spi_new;
+
+ DBG2(DBG_ESP, "allocating SPI for reqid {%u}", reqid);
+
+ this->mutex->lock(this->mutex);
+ if (!this->rng)
+ {
+ this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!this->rng)
+ {
+ this->mutex->unlock(this->mutex);
+ DBG1(DBG_ESP, "failed to create RNG for SPI generation");
+ return FAILED;
+ }
+ }
+
+ do
+ {
+ if (!this->rng->get_bytes(this->rng, sizeof(spi_new),
+ (u_int8_t*)&spi_new))
+ {
+ this->mutex->unlock(this->mutex);
+ DBG1(DBG_ESP, "failed to allocate SPI for reqid {%u}", reqid);
+ return FAILED;
+ }
+ /* make sure the SPI is valid (not in range 0-255) */
+ spi_new |= 0x00000100;
+ spi_new = htonl(spi_new);
+ }
+ while (!allocate_spi(this, spi_new));
+ this->mutex->unlock(this->mutex);
+
+ *spi = spi_new;
+
+ DBG2(DBG_ESP, "allocated SPI %.8x for reqid {%u}", ntohl(*spi), reqid);
+ return SUCCESS;
+}
+
+METHOD(ipsec_sa_mgr_t, add_sa, status_t,
+ private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi,
+ u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc,
+ lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
+ u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+ u_int16_t cpi, bool encap, bool esn, bool inbound,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+{
+ ipsec_sa_entry_t *entry;
+ ipsec_sa_t *sa_new;
+
+ DBG2(DBG_ESP, "adding SAD entry with SPI %.8x and reqid {%u}",
+ ntohl(spi), reqid);
+ DBG2(DBG_ESP, " using encryption algorithm %N with key size %d",
+ encryption_algorithm_names, enc_alg, enc_key.len * 8);
+ DBG2(DBG_ESP, " using integrity algorithm %N with key size %d",
+ integrity_algorithm_names, int_alg, int_key.len * 8);
+
+ sa_new = ipsec_sa_create(spi, src, dst, protocol, reqid, mark, tfc,
+ lifetime, enc_alg, enc_key, int_alg, int_key, mode,
+ ipcomp, cpi, encap, esn, inbound, src_ts, dst_ts);
+ if (!sa_new)
+ {
+ DBG1(DBG_ESP, "failed to create SAD entry");
+ return FAILED;
+ }
+
+ this->mutex->lock(this->mutex);
+
+ if (inbound)
+ { /* remove any pre-allocated SPIs */
+ u_int32_t *spi_alloc;
+
+ spi_alloc = this->allocated_spis->remove(this->allocated_spis, &spi);
+ free(spi_alloc);
+ }
+
+ if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst,
+ NULL, spi, src, dst) == SUCCESS)
+ {
+ this->mutex->unlock(this->mutex);
+ DBG1(DBG_ESP, "failed to install SAD entry: already installed");
+ sa_new->destroy(sa_new);
+ return FAILED;
+ }
+
+ entry = create_entry(sa_new);
+ schedule_expiration(this, entry);
+ this->sas->insert_last(this->sas, entry);
+
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+}
+
+METHOD(ipsec_sa_mgr_t, del_sa, status_t,
+ private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi,
+ u_int8_t protocol, u_int16_t cpi, mark_t mark)
+{
+ ipsec_sa_entry_t *current, *found = NULL;
+ enumerator_t *enumerator;
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->sas->create_enumerator(this->sas);
+ while (enumerator->enumerate(enumerator, (void**)&current))
+ {
+ if (match_entry_by_spi_src_dst(current, spi, src, dst))
+ {
+ if (wait_remove_entry(this, current))
+ {
+ this->sas->remove_at(this->sas, enumerator);
+ found = current;
+ }
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+
+ if (found)
+ {
+ DBG2(DBG_ESP, "deleted %sbound SAD entry with SPI %.8x",
+ found->sa->is_inbound(found->sa) ? "in" : "out", ntohl(spi));
+ destroy_entry(found);
+ return SUCCESS;
+ }
+ return FAILED;
+}
+
+METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*,
+ private_ipsec_sa_mgr_t *this, u_int32_t reqid, bool inbound)
+{
+ ipsec_sa_entry_t *entry;
+ ipsec_sa_t *sa = NULL;
+
+ this->mutex->lock(this->mutex);
+ if (this->sas->find_first(this->sas, (void*)match_entry_by_reqid_inbound,
+ (void**)&entry, reqid, inbound) == SUCCESS &&
+ wait_for_entry(this, entry))
+ {
+ sa = entry->sa;
+ }
+ this->mutex->unlock(this->mutex);
+ return sa;
+}
+
+METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*,
+ private_ipsec_sa_mgr_t *this, u_int32_t spi, host_t *dst)
+{
+ ipsec_sa_entry_t *entry;
+ ipsec_sa_t *sa = NULL;
+
+ this->mutex->lock(this->mutex);
+ if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_dst,
+ (void**)&entry, spi, dst) == SUCCESS &&
+ wait_for_entry(this, entry))
+ {
+ sa = entry->sa;
+ }
+ this->mutex->unlock(this->mutex);
+ return sa;
+}
+
+METHOD(ipsec_sa_mgr_t, checkin, void,
+ private_ipsec_sa_mgr_t *this, ipsec_sa_t *sa)
+{
+ ipsec_sa_entry_t *entry;
+
+ this->mutex->lock(this->mutex);
+ if (this->sas->find_first(this->sas, (void*)match_entry_by_sa_ptr,
+ (void**)&entry, sa) == SUCCESS)
+ {
+ if (entry->locked)
+ {
+ entry->locked = FALSE;
+ entry->condvar->signal(entry->condvar);
+ }
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(ipsec_sa_mgr_t, flush_sas, status_t,
+ private_ipsec_sa_mgr_t *this)
+{
+ this->mutex->lock(this->mutex);
+ flush_entries(this);
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+}
+
+METHOD(ipsec_sa_mgr_t, destroy, void,
+ private_ipsec_sa_mgr_t *this)
+{
+ this->mutex->lock(this->mutex);
+ flush_entries(this);
+ flush_allocated_spis(this);
+ this->mutex->unlock(this->mutex);
+
+ this->allocated_spis->destroy(this->allocated_spis);
+ this->sas->destroy(this->sas);
+
+ this->mutex->destroy(this->mutex);
+ DESTROY_IF(this->rng);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+ipsec_sa_mgr_t *ipsec_sa_mgr_create()
+{
+ private_ipsec_sa_mgr_t *this;
+
+ INIT(this,
+ .public = {
+ .get_spi = _get_spi,
+ .add_sa = _add_sa,
+ .del_sa = _del_sa,
+ .checkout_by_spi = _checkout_by_spi,
+ .checkout_by_reqid = _checkout_by_reqid,
+ .checkin = _checkin,
+ .flush_sas = _flush_sas,
+ .destroy = _destroy,
+ },
+ .sas = linked_list_create(),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .allocated_spis = hashtable_create((hashtable_hash_t)spi_hash,
+ (hashtable_equals_t)spi_equals, 16),
+ );
+
+ return &this->public;
+}
diff --git a/src/libipsec/ipsec_sa_mgr.h b/src/libipsec/ipsec_sa_mgr.h
new file mode 100644
index 000000000..303b36f0e
--- /dev/null
+++ b/src/libipsec/ipsec_sa_mgr.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_sa_mgr ipsec_sa_mgr
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_SA_MGR_H_
+#define IPSEC_SA_MGR_H_
+
+#include "ipsec_sa.h"
+
+#include <library.h>
+#include <ipsec/ipsec_types.h>
+#include <selectors/traffic_selector.h>
+#include <utils/host.h>
+
+typedef struct ipsec_sa_mgr_t ipsec_sa_mgr_t;
+
+/**
+ * IPsec SA manager
+ *
+ * The first methods are modeled after those in kernel_ipsec_t.
+ */
+struct ipsec_sa_mgr_t {
+
+ /**
+ * Allocate an SPI for an inbound IPsec SA
+ *
+ * @param src source address of the SA
+ * @param dst destination address of the SA
+ * @param protocol protocol of the SA (only ESP supported)
+ * @param reqid reqid for the SA
+ * @param spi the allocated SPI
+ * @return SUCCESS of operation successful
+ */
+ status_t (*get_spi)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst,
+ u_int8_t protocol, u_int32_t reqid, u_int32_t *spi);
+
+ /**
+ * Add a new SA
+ *
+ * @param src source address for this SA (gets cloned)
+ * @param dst destination address for this SA (gets cloned)
+ * @param spi SPI for this SA
+ * @param protocol protocol for this SA (only ESP is supported)
+ * @param reqid reqid for this SA
+ * @param mark mark for this SA (ignored)
+ * @param tfc Traffic Flow Confidentiality (not yet supported)
+ * @param lifetime lifetime for this SA
+ * @param enc_alg encryption algorithm for this SA
+ * @param enc_key encryption key for this SA
+ * @param int_alg integrity protection algorithm
+ * @param int_key integrity protection key
+ * @param mode mode for this SA (only tunnel mode is supported)
+ * @param ipcomp IPcomp transform (not supported, use IPCOMP_NONE)
+ * @param cpi CPI for IPcomp (ignored)
+ * @param encap enable UDP encapsulation (must be TRUE)
+ * @param esn Extended Sequence Numbers (currently not supported)
+ * @param inbound TRUE if this is an inbound SA, FALSE otherwise
+ * @param src_ts source traffic selector
+ * @param dst_ts destination traffic selector
+ * @return SUCCESS if operation completed
+ */
+ status_t (*add_sa)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst,
+ u_int32_t spi, u_int8_t protocol, u_int32_t reqid,
+ mark_t mark, u_int32_t tfc, lifetime_cfg_t *lifetime,
+ u_int16_t enc_alg, chunk_t enc_key, u_int16_t int_alg,
+ chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+ u_int16_t cpi, bool encap, bool esn, bool inbound,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
+
+ /**
+ * Delete a previously added SA
+ *
+ * @param spi SPI of the SA
+ * @param src source address of the SA
+ * @param dst destination address of the SA
+ * @param protocol protocol of the SA
+ * @param cpi CPI for IPcomp
+ * @param mark optional mark
+ * @return SUCCESS if operation completed
+ */
+ status_t (*del_sa)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst,
+ u_int32_t spi, u_int8_t protocol, u_int16_t cpi,
+ mark_t mark);
+
+ /**
+ * Flush all SAs
+ *
+ * @return SUCCESS if operation completed
+ */
+ status_t (*flush_sas)(ipsec_sa_mgr_t *this);
+
+ /**
+ * Checkout an installed IPsec SA by SPI and destination address
+ * Can be used to find the correct SA for an inbound packet.
+ *
+ * The matching SA is locked until it is checked in using checkin().
+ * If the matching SA is already checked out, this call blocks until the
+ * SA is checked in.
+ *
+ * Since other threads may be waiting for the checked out SA, it should be
+ * checked in as soon as possible after use.
+ *
+ * @param spi SPI (e.g. of an inbound packet)
+ * @param dst destination address (e.g. of an inbound packet)
+ * @return the matching IPsec SA, or NULL if none is found
+ */
+ ipsec_sa_t *(*checkout_by_spi)(ipsec_sa_mgr_t *this, u_int32_t spi,
+ host_t *dst);
+
+ /**
+ * Checkout an installed IPsec SA by its reqid and inbound/outbound flag.
+ * Can be used to find the correct SA for an outbound packet.
+ *
+ * The matching SA is locked until it is checked in using checkin().
+ * If the matching SA is already checked out, this call blocks until the
+ * SA is checked in.
+ *
+ * Since other threads may be waiting for a checked out SA, it should be
+ * checked in as soon as possible after use.
+ *
+ * @param reqid reqid of the SA
+ * @param inbound TRUE for an inbound SA, FALSE for an outbound SA
+ * @return the matching IPsec SA, or NULL if none is found
+ */
+ ipsec_sa_t *(*checkout_by_reqid)(ipsec_sa_mgr_t *this, u_int32_t reqid,
+ bool inbound);
+
+ /**
+ * Checkin an SA after use.
+ *
+ * @param sa checked out SA
+ */
+ void (*checkin)(ipsec_sa_mgr_t *this, ipsec_sa_t *sa);
+
+ /**
+ * Destroy an ipsec_sa_mgr_t
+ */
+ void (*destroy)(ipsec_sa_mgr_t *this);
+
+};
+
+/**
+ * Create an ipsec_sa_mgr instance
+ *
+ * @return IPsec SA manager instance
+ */
+ipsec_sa_mgr_t *ipsec_sa_mgr_create();
+
+#endif /** IPSEC_SA_MGR_H_ @}*/