diff options
Diffstat (limited to 'src/pluto')
48 files changed, 1648 insertions, 5061 deletions
diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index 9f631ca28..934b11a46 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -18,6 +18,7 @@ db_ops.c db_ops.h \ defs.c defs.h \ demux.c demux.h \ dnskey.c dnskey.h \ +event_queue.c event_queue.h \ fetch.c fetch.h \ foodgroups.c foodgroups.h \ ike_alg.c ike_alg.h \ @@ -25,8 +26,6 @@ ipsec_doi.c ipsec_doi.h \ kameipsec.h \ kernel.c kernel.h \ kernel_alg.c kernel_alg.h \ -kernel_netlink.c kernel_netlink.h \ -kernel_noklips.c kernel_noklips.h \ kernel_pfkey.c kernel_pfkey.h \ keys.c keys.h \ lex.c lex.h \ @@ -74,10 +73,10 @@ AM_CFLAGS = -rdynamic \ -DIPSEC_CONFDIR=\"${sysconfdir}\" \ -DIPSEC_PIDDIR=\"${piddir}\" \ -DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ --DPLUGINS=\""${pluto_plugins} ${libhydra_plugins}\"" \ +-DPLUGINS=\""${pluto_plugins}\"" \ -DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" \ -DKERNEL26_SUPPORT -DKERNEL26_HAS_KAME_DUPLICATES \ --DPLUTO -DKLIPS -DDEBUG +-DPLUTO -DDEBUG pluto_LDADD = \ $(LIBSTRONGSWANDIR)/libstrongswan.la \ @@ -89,9 +88,7 @@ _pluto_adns_LDADD = \ $(LIBFREESWANDIR)/libfreeswan.a \ -lresolv $(DLLIB) -CLEANFILES = ipsec.secrets.5 -dist_man_MANS = pluto.8 ipsec.secrets.5 -EXTRA_DIST = ipsec.secrets.5.in +dist_man_MANS = pluto.8 # compile options ################# @@ -138,8 +135,3 @@ if USE_XAUTH SUBDIRS += plugins/xauth endif -ipsec.secrets.5 : ipsec.secrets.5.in - sed \ - -e "s:@IPSEC_VERSION@:$(PACKAGE_VERSION):" \ - $(srcdir)/$@.in > $@ - diff --git a/src/pluto/Makefile.in b/src/pluto/Makefile.in index 41fc4927e..080530f86 100644 --- a/src/pluto/Makefile.in +++ b/src/pluto/Makefile.in @@ -71,14 +71,14 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.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_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = -am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" \ - "$(DESTDIR)$(man8dir)" +am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)" PROGRAMS = $(ipsec_PROGRAMS) am__pluto_adns_OBJECTS = adns.$(OBJEXT) _pluto_adns_OBJECTS = $(am__pluto_adns_OBJECTS) @@ -89,17 +89,17 @@ am_pluto_OBJECTS = ac.$(OBJEXT) alg_info.$(OBJEXT) ca.$(OBJEXT) \ certs.$(OBJEXT) connections.$(OBJEXT) constants.$(OBJEXT) \ cookie.$(OBJEXT) crl.$(OBJEXT) crypto.$(OBJEXT) \ db_ops.$(OBJEXT) defs.$(OBJEXT) demux.$(OBJEXT) \ - dnskey.$(OBJEXT) fetch.$(OBJEXT) foodgroups.$(OBJEXT) \ - ike_alg.$(OBJEXT) ipsec_doi.$(OBJEXT) kernel.$(OBJEXT) \ - kernel_alg.$(OBJEXT) kernel_netlink.$(OBJEXT) \ - kernel_noklips.$(OBJEXT) kernel_pfkey.$(OBJEXT) keys.$(OBJEXT) \ - lex.$(OBJEXT) log.$(OBJEXT) myid.$(OBJEXT) modecfg.$(OBJEXT) \ - nat_traversal.$(OBJEXT) ocsp.$(OBJEXT) packet.$(OBJEXT) \ - pkcs7.$(OBJEXT) pluto.$(OBJEXT) plutomain.$(OBJEXT) \ - rcv_whack.$(OBJEXT) server.$(OBJEXT) smartcard.$(OBJEXT) \ - spdb.$(OBJEXT) state.$(OBJEXT) timer.$(OBJEXT) \ - vendor.$(OBJEXT) virtual.$(OBJEXT) whack_attribute.$(OBJEXT) \ - xauth_manager.$(OBJEXT) x509.$(OBJEXT) builder.$(OBJEXT) + dnskey.$(OBJEXT) event_queue.$(OBJEXT) fetch.$(OBJEXT) \ + foodgroups.$(OBJEXT) ike_alg.$(OBJEXT) ipsec_doi.$(OBJEXT) \ + kernel.$(OBJEXT) kernel_alg.$(OBJEXT) kernel_pfkey.$(OBJEXT) \ + keys.$(OBJEXT) lex.$(OBJEXT) log.$(OBJEXT) myid.$(OBJEXT) \ + modecfg.$(OBJEXT) nat_traversal.$(OBJEXT) ocsp.$(OBJEXT) \ + packet.$(OBJEXT) pkcs7.$(OBJEXT) pluto.$(OBJEXT) \ + plutomain.$(OBJEXT) rcv_whack.$(OBJEXT) server.$(OBJEXT) \ + smartcard.$(OBJEXT) spdb.$(OBJEXT) state.$(OBJEXT) \ + timer.$(OBJEXT) vendor.$(OBJEXT) virtual.$(OBJEXT) \ + whack_attribute.$(OBJEXT) xauth_manager.$(OBJEXT) \ + x509.$(OBJEXT) builder.$(OBJEXT) pluto_OBJECTS = $(am_pluto_OBJECTS) pluto_DEPENDENCIES = $(LIBSTRONGSWANDIR)/libstrongswan.la \ $(LIBFREESWANDIR)/libfreeswan.a $(LIBHYDRADIR)/libhydra.la \ @@ -148,7 +148,6 @@ am__nobase_list = $(am__nobase_strip_setup); \ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(dist_man_MANS) @@ -251,6 +250,8 @@ 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@ @@ -282,14 +283,17 @@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ +c_plugins = @c_plugins@ datadir = @datadir@ datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ default_pkcs11 = @default_pkcs11@ 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@ @@ -304,24 +308,31 @@ ipsecgid = @ipsecgid@ ipsecgroup = @ipsecgroup@ ipsecuid = @ipsecuid@ ipsecuser = @ipsecuser@ +libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ -libhydra_plugins = @libhydra_plugins@ -libstrongswan_plugins = @libstrongswan_plugins@ 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@ oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ pdfdir = @pdfdir@ piddir = @piddir@ +pki_plugins = @pki_plugins@ plugindir = @plugindir@ pluto_plugins = @pluto_plugins@ +pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ @@ -329,7 +340,10 @@ 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@ srcdir = @srcdir@ strongswan_conf = @strongswan_conf@ @@ -355,6 +369,7 @@ db_ops.c db_ops.h \ defs.c defs.h \ demux.c demux.h \ dnskey.c dnskey.h \ +event_queue.c event_queue.h \ fetch.c fetch.h \ foodgroups.c foodgroups.h \ ike_alg.c ike_alg.h \ @@ -362,8 +377,6 @@ ipsec_doi.c ipsec_doi.h \ kameipsec.h \ kernel.c kernel.h \ kernel_alg.c kernel_alg.h \ -kernel_netlink.c kernel_netlink.h \ -kernel_noklips.c kernel_noklips.h \ kernel_pfkey.c kernel_pfkey.h \ keys.c keys.h \ lex.c lex.h \ @@ -405,11 +418,11 @@ INCLUDES = \ AM_CFLAGS = -rdynamic -DIPSEC_DIR=\"${ipsecdir}\" \ -DIPSEC_CONFDIR=\"${sysconfdir}\" -DIPSEC_PIDDIR=\"${piddir}\" \ -DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ - -DPLUGINS=\""${pluto_plugins} ${libhydra_plugins}\"" \ + -DPLUGINS=\""${pluto_plugins}\"" \ -DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" -DKERNEL26_SUPPORT \ - -DKERNEL26_HAS_KAME_DUPLICATES -DPLUTO -DKLIPS -DDEBUG \ - $(am__append_1) $(am__append_2) $(am__append_3) \ - $(am__append_4) $(am__append_5) $(am__append_7) + -DKERNEL26_HAS_KAME_DUPLICATES -DPLUTO -DDEBUG $(am__append_1) \ + $(am__append_2) $(am__append_3) $(am__append_4) \ + $(am__append_5) $(am__append_7) pluto_LDADD = $(LIBSTRONGSWANDIR)/libstrongswan.la \ $(LIBFREESWANDIR)/libfreeswan.a $(LIBHYDRADIR)/libhydra.la \ -lresolv $(PTHREADLIB) $(DLLIB) $(am__append_6) @@ -417,9 +430,7 @@ _pluto_adns_LDADD = \ $(LIBFREESWANDIR)/libfreeswan.a \ -lresolv $(DLLIB) -CLEANFILES = ipsec.secrets.5 -dist_man_MANS = pluto.8 ipsec.secrets.5 -EXTRA_DIST = ipsec.secrets.5.in +dist_man_MANS = pluto.8 # build optional plugins ######################## @@ -529,14 +540,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/demux.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnskey.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/foodgroups.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_doi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_alg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_netlink.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_noklips.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_pfkey.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lex.Po@am__quote@ @@ -601,44 +611,6 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -install-man5: $(dist_man_MANS) - @$(NORMAL_INSTALL) - test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)" - @list=''; test -n "$(man5dir)" || exit 0; \ - { for i in $$list; do echo "$$i"; done; \ - l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ - sed -n '/\.5[a-z]*$$/p'; \ - } | while read p; do \ - if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; echo "$$p"; \ - done | \ - sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ - -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ - sed 'N;N;s,\n, ,g' | { \ - list=; while read file base inst; do \ - if test "$$base" = "$$inst"; then list="$$list $$file"; else \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ - fi; \ - done; \ - for i in $$list; do echo "$$i"; done | $(am__base_list) | \ - while read files; do \ - test -z "$$files" || { \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ - done; } - -uninstall-man5: - @$(NORMAL_UNINSTALL) - @list=''; test -n "$(man5dir)" || exit 0; \ - files=`{ for i in $$list; do echo "$$i"; done; \ - l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ - sed -n '/\.5[a-z]*$$/p'; \ - } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ - -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ - test -z "$$files" || { \ - echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(man5dir)" && rm -f $$files; } install-man8: $(dist_man_MANS) @$(NORMAL_INSTALL) test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" @@ -889,7 +861,7 @@ check: check-recursive all-am: Makefile $(PROGRAMS) $(MANS) installdirs: installdirs-recursive installdirs-am: - for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \ + for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive @@ -909,7 +881,6 @@ install-strip: mostlyclean-generic: clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -957,7 +928,7 @@ install-info: install-info-recursive install-info-am: -install-man: install-man5 install-man8 +install-man: install-man8 install-pdf: install-pdf-recursive @@ -989,7 +960,7 @@ ps-am: uninstall-am: uninstall-ipsecPROGRAMS uninstall-man -uninstall-man: uninstall-man5 uninstall-man8 +uninstall-man: uninstall-man8 .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive @@ -1002,24 +973,18 @@ uninstall-man: uninstall-man5 uninstall-man8 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-ipsecPROGRAMS install-man install-man5 \ - install-man8 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-ipsecPROGRAMS uninstall-man uninstall-man5 \ + install-info-am install-ipsecPROGRAMS install-man install-man8 \ + 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-ipsecPROGRAMS uninstall-man \ uninstall-man8 plutomain.o : $(top_builddir)/config.status -ipsec.secrets.5 : ipsec.secrets.5.in - sed \ - -e "s:@IPSEC_VERSION@:$(PACKAGE_VERSION):" \ - $(srcdir)/$@.in > $@ - # 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/pluto/alg_info.c b/src/pluto/alg_info.c index 32fd46ef4..d06e09007 100644 --- a/src/pluto/alg_info.c +++ b/src/pluto/alg_info.c @@ -414,7 +414,7 @@ struct alg_info_esp *alg_info_esp_create_from_str(char *alg_str) alg_info_esp = malloc_thing (struct alg_info_esp); zero(alg_info_esp); - pfs_name=index (alg_str, ';'); + pfs_name=strchr(alg_str, ';'); if (pfs_name) { memcpy(esp_buf, alg_str, pfs_name-alg_str); diff --git a/src/pluto/builder.c b/src/pluto/builder.c index 0cba32bcf..d7ec3feb9 100644 --- a/src/pluto/builder.c +++ b/src/pluto/builder.c @@ -136,9 +136,9 @@ static x509crl_t *builder_load_crl(certificate_type_t type, va_list args) void init_builder(void) { - lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, FALSE, (builder_function_t)builder_load_cert); - lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, FALSE, (builder_function_t)builder_load_crl); } diff --git a/src/pluto/certs.c b/src/pluto/certs.c index 24e8ffb27..e866022df 100644 --- a/src/pluto/certs.c +++ b/src/pluto/certs.c @@ -74,20 +74,21 @@ void cert_free(cert_t *cert) cert_t* cert_add(cert_t *cert) { certificate_t *certificate = cert->cert; - cert_t *c = certs; + cert_t *c; - while (c != NULL) + lock_certs_and_keys("cert_add"); + + for (c = certs; c != NULL; c = c->next) { - if (certificate->equals(certificate, c->cert)) /* already in chain, free cert */ - { + if (certificate->equals(certificate, c->cert)) + { /* already in chain, free cert */ + unlock_certs_and_keys("cert_add"); cert_free(cert); return c; } - c = c->next; } /* insert new cert at the root of the chain */ - lock_certs_and_keys("cert_add"); cert->next = certs; certs = cert; DBG(DBG_CONTROL | DBG_PARSING, @@ -98,90 +99,6 @@ cert_t* cert_add(cert_t *cert) } /** - * Passphrase callback to read from whack fd - */ -chunk_t whack_pass_cb(prompt_pass_t *pass, int try) -{ - int n; - - if (try > MAX_PROMPT_PASS_TRIALS) - { - whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials"); - return chunk_empty; - } - if (try == 1) - { - whack_log(RC_ENTERSECRET, "need passphrase for 'private key'"); - } - else - { - whack_log(RC_ENTERSECRET, "invalid passphrase, please try again"); - } - - n = read(pass->fd, pass->secret, PROMPT_PASS_LEN); - - if (n == -1) - { - whack_log(RC_LOG_SERIOUS, "read(whackfd) failed"); - return chunk_empty; - } - - pass->secret[n-1] = '\0'; - - if (strlen(pass->secret) == 0) - { - whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted"); - return chunk_empty; - } - return chunk_create(pass->secret, strlen(pass->secret)); -} - -/** - * Loads a PKCS#1 or PGP private key file - */ -private_key_t* load_private_key(char* filename, prompt_pass_t *pass, - key_type_t type) -{ - private_key_t *key = NULL; - char *path; - - path = concatenate_paths(PRIVATE_KEY_PATH, filename); - if (pass && pass->prompt && pass->fd != NULL_FD) - { /* use passphrase callback */ - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, - BUILD_PASSPHRASE_CALLBACK, whack_pass_cb, pass, - BUILD_END); - if (key) - { - whack_log(RC_SUCCESS, "valid passphrase"); - } - } - else if (pass) - { /* use a given passphrase */ - chunk_t password = chunk_create(pass->secret, strlen(pass->secret)); - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, - BUILD_PASSPHRASE, password, BUILD_END); - } - else - { /* no passphrase */ - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - - } - if (key) - { - plog(" loaded private key from '%s'", filename); - } - else - { - plog(" syntax error in private key file"); - } - return key; -} - -/** * Loads a X.509 or OpenPGP certificate */ cert_t* load_cert(char *filename, const char *label, x509_flag_t flags) @@ -316,7 +233,7 @@ void list_pgp_end_certs(bool utc) whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", key_type_names, key->get_type(key), - key->get_keysize(key) * BITS_PER_BYTE, + key->get_keysize(key), has_private_key(cert)? ", has private key" : ""); if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &keyid)) { diff --git a/src/pluto/certs.h b/src/pluto/certs.h index 21e856a3c..b31c4c3ed 100644 --- a/src/pluto/certs.h +++ b/src/pluto/certs.h @@ -65,8 +65,6 @@ extern const cert_t cert_empty; */ extern bool no_cr_send; -extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass, - key_type_t type); extern cert_t* load_cert(char *filename, const char *label, x509_flag_t flags); extern cert_t* load_host_cert(char *filename); extern cert_t* load_ca_cert(char *filename); diff --git a/src/pluto/connections.c b/src/pluto/connections.c index e1f47f2d6..9f277e135 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -297,6 +297,7 @@ void delete_connection(connection_t *c, bool relations) { modecfg_attribute_t *ca; connection_t *old_cur_connection; + identification_t *client_id; old_cur_connection = cur_connection == c? NULL : cur_connection; #ifdef DEBUG @@ -367,12 +368,14 @@ void delete_connection(connection_t *c, bool relations) free(c->spd.that.virt); } + client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; + /* release virtual IP address lease if any */ if (c->spd.that.modecfg && c->spd.that.pool && !c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) { hydra->attributes->release_address(hydra->attributes, c->spd.that.pool, - c->spd.that.host_srcip, c->spd.that.id); + c->spd.that.host_srcip, client_id); } /* release requested attributes if any */ @@ -388,7 +391,7 @@ void delete_connection(connection_t *c, bool relations) while (c->attributes->remove_last(c->attributes, (void **)&ca) == SUCCESS) { hydra->attributes->release(hydra->attributes, ca->handler, - c->spd.that.id, ca->type, ca->value); + client_id, ca->type, ca->value); modecfg_attribute_destroy(ca); } c->attributes->destroy(c->attributes); @@ -536,7 +539,7 @@ void check_orientations(void) for (hp = host_pairs; hp != NULL; hp = hp->next) { if (sameaddr(&hp->him.addr, &i->addr) - && (!no_klips || hp->him.port == pluto_port)) + && hp->him.port == pluto_port) { /* bad news: the whole chain of connections * hanging off this host pair has both sides @@ -871,7 +874,8 @@ static void load_end_certificate(char *filename, struct end *dst) /* cache the certificate that was last retrieved from the smartcard */ if (dst->sc) { - if (!certificate->equals(certificate, dst->sc->last_cert->cert)) + if (!dst->sc->last_cert || + !certificate->equals(certificate, dst->sc->last_cert->cert)) { lock_certs_and_keys("load_end_certificates"); cert_release(dst->sc->last_cert); @@ -1077,7 +1081,7 @@ void add_connection(const whack_message_t *wm) if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp) { loglog(RC_COMMENT - , "ignoring --compress in \"%s\" because KLIPS is not configured to do IPCOMP" + , "ignoring --compress in \"%s\" because kernel does not support IPCOMP" , c->name); } @@ -1191,7 +1195,12 @@ void add_connection(const whack_message_t *wm) } c->spd.next = NULL; - c->spd.reqid = gen_reqid(); + c->spd.reqid = wm->reqid ?: gen_reqid(); + + c->spd.mark_in.value = wm->mark_in.value; + c->spd.mark_in.mask = wm->mark_in.mask; + c->spd.mark_out.value = wm->mark_out.value; + c->spd.mark_out.mask = wm->mark_out.mask; /* set internal fields */ c->instance_serial = 0; @@ -1884,7 +1893,7 @@ bool orient(connection_t *c) { /* check if this interface matches this end */ if (sameaddr(&sr->this.host_addr, &p->addr) - && (!no_klips || sr->this.host_port == pluto_port)) + && sr->this.host_port == pluto_port) { if (oriented(*c)) { @@ -1903,7 +1912,7 @@ bool orient(connection_t *c) /* done with this interface if it doesn't match that end */ if (!(sameaddr(&sr->that.host_addr, &p->addr) - && (!no_klips || sr->that.host_port == pluto_port))) + && sr->that.host_port == pluto_port)) break; /* swap ends and try again. @@ -2146,27 +2155,6 @@ static void cannot_oppo(connection_t *c, struct find_oppo_bundle *b, err_t ugh) } return; } - -#ifdef KLIPS - if (b->held) - { - /* Replace HOLD with b->failure_shunt. - * If no b->failure_shunt specified, use SPI_PASS -- THIS MAY CHANGE. - */ - if (b->failure_shunt == 0) - { - DBG(DBG_OPPO, DBG_log("no explicit failure shunt for %s to %s; installing %%pass" - , ocb, pcb)); - } - - (void) replace_bare_shunt(&b->our_client, &b->peer_client - , b->policy_prio - , b->failure_shunt - , b->failure_shunt != 0 - , b->transport_proto - , ugh); - } -#endif } static void initiate_opportunistic_body(struct find_oppo_bundle *b @@ -2203,16 +2191,6 @@ static void continue_oppo(struct adns_continuation *acr, err_t ugh) */ whack_log_fd = whackfd; -#ifdef KLIPS - /* Discover and record whether %hold has gone away. - * This could have happened while we were awaiting DNS. - * We must check BEFORE any call to cannot_oppo. - */ - if (was_held) - cr->b.held = has_bare_hold(&cr->b.our_client, &cr->b.peer_client - , cr->b.transport_proto); -#endif - #ifdef DEBUG /* if we're going to ignore the error, at least note it in debugging log */ if (cr->b.failure_ok && ugh) @@ -2424,7 +2402,7 @@ static void initiate_opportunistic_body(struct find_oppo_bundle *b, /* We've found a connection that can serve. * Do we have to initiate it? * Not if there is currently an IPSEC SA. - * But if there is an IPSEC SA, then KLIPS would not + * But if there is an IPSEC SA, then the kernel would not * have generated the acquire. So we assume that there isn't one. * This may be redundant if a non-opportunistic * negotiation is already being attempted. @@ -2445,13 +2423,11 @@ static void initiate_opportunistic_body(struct find_oppo_bundle *b, /* otherwise, there is some kind of static conn that can handle * this connection, so we initiate it */ -#ifdef KLIPS if (b->held) { /* what should we do on failure? */ (void) assign_hold(c, sr, b->transport_proto, &b->our_client, &b->peer_client); } -#endif ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); b->whackfd = NULL_FD; /* protect from close */ } @@ -2816,21 +2792,6 @@ static void initiate_opportunistic_body(struct find_oppo_bundle *b, "no suitable connection for opportunism " "between %s and %s with %Y as peer", ocb, pcb, ac->gateways_from_dns->gw_id); - -#ifdef KLIPS - if (b->held) - { - /* Replace HOLD with PASS. - * The type of replacement *ought* to be - * specified by policy. - */ - (void) replace_bare_shunt(&b->our_client, &b->peer_client - , BOTTOM_PRIO - , SPI_PASS /* fail into PASS */ - , TRUE, b->transport_proto - , "no suitable connection"); - } -#endif } else { @@ -2839,7 +2800,6 @@ static void initiate_opportunistic_body(struct find_oppo_bundle *b, passert(c->gw_info != NULL); passert(HAS_IPSEC_POLICY(c->policy)); passert(LHAS(LELEM(RT_UNROUTED) | LELEM(RT_ROUTED_PROSPECTIVE), c->spd.routing)); -#ifdef KLIPS if (b->held) { /* what should we do on failure? */ @@ -2847,7 +2807,6 @@ static void initiate_opportunistic_body(struct find_oppo_bundle *b, , b->transport_proto , &b->our_client, &b->peer_client); } -#endif c->gw_info->key->last_tried_time = now(); ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); b->whackfd = NULL_FD; /* protect from close */ @@ -3161,6 +3120,10 @@ connection_t *route_owner(connection_t *c, struct spd_route **srp, { continue; } + if (src->mark_out.value != srd->mark_out.value) + { + continue; + } passert(oriented(*d)); if (srd->routing > best_routing) { @@ -3181,6 +3144,10 @@ connection_t *route_owner(connection_t *c, struct spd_route **srp, { continue; } + if (src->mark_in.value != srd->mark_in.value) + { + continue; + } if (srd->routing > best_erouting) { best_ero = d; diff --git a/src/pluto/connections.h b/src/pluto/connections.h index b67f0b562..e3775fcb0 100644 --- a/src/pluto/connections.h +++ b/src/pluto/connections.h @@ -168,6 +168,8 @@ struct spd_route { so_serial_t eroute_owner; enum routing_t routing; /* level of routing in place */ uint32_t reqid; + mark_t mark_in; + mark_t mark_out; }; typedef struct connection connection_t; @@ -294,7 +296,7 @@ extern connection_t* find_connection_for_clients(struct spd_route **srp, const ip_address *peer_client, int transport_proto); extern void get_peer_ca_and_groups(connection_t *c, - identification_t **peer_ca, + identification_t **peer_ca, ietf_attributes_t **peer_attributes); /* instantiating routines diff --git a/src/pluto/constants.c b/src/pluto/constants.c index 63a37009b..ec7bfaf78 100644 --- a/src/pluto/constants.c +++ b/src/pluto/constants.c @@ -77,7 +77,6 @@ ENUM(dpd_action_names, DPD_ACTION_NONE, DPD_ACTION_RESTART, ENUM(timer_event_names, EVENT_NULL, EVENT_LOG_DAILY, "EVENT_NULL", "EVENT_REINIT_SECRET", - "EVENT_SHUNT_SCAN", "EVENT_SO_DISCARD", "EVENT_RETRANSMIT", "EVENT_SA_REPLACE", @@ -112,7 +111,7 @@ const char *const debug_bit_names[] = { "emitting", "control", "lifecycle", - "klips", + "kernel", "dns", "natt", "oppo", @@ -132,6 +131,8 @@ const char *const debug_bit_names[] = { /* State of exchanges */ static const char *const state_name[] = { + "STATE_UNDEFINED", + "STATE_MAIN_R0", "STATE_MAIN_I1", "STATE_MAIN_R1", @@ -171,11 +172,12 @@ static const char *const state_name[] = { }; enum_names state_names = - { STATE_MAIN_R0, STATE_IKE_ROOF-1, state_name, NULL }; + { STATE_UNDEFINED, STATE_IKE_ROOF-1, state_name, NULL }; /* story for state */ const char *const state_story[] = { + "undefined state after error", /* STATE_UNDEFINED */ "expecting MI1", /* STATE_MAIN_R0 */ "sent MI1, expecting MR1", /* STATE_MAIN_I1 */ "sent MR1, expecting MI2", /* STATE_MAIN_R1 */ @@ -411,7 +413,7 @@ enum_names esp_transform_names = static const char *const ipcomp_transform_name[] = { "IPCOMP_OUI", - "IPCOMP_DEFLAT", + "IPCOMP_DEFLATE", "IPCOMP_LZS", "IPCOMP_LZJH", }; diff --git a/src/pluto/constants.h b/src/pluto/constants.h index 790bbefa6..075579d6d 100644 --- a/src/pluto/constants.h +++ b/src/pluto/constants.h @@ -18,6 +18,8 @@ #include <freeswan.h> +#include <kernel/kernel_ipsec.h> + #include <utils.h> #include <utils/identification.h> #include <crypto/hashers/hasher.h> @@ -193,16 +195,9 @@ extern enum_names esp_transform_names; /* IPCOMP transform values * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5 + * now defined in kernel/kernel_ipsec.h */ -enum ipsec_comp_algo { - IPSCOMP_NONE = 0, - IPCOMP_OUI = 1, - IPCOMP_DEFLATE = 2, - IPCOMP_LZS = 3, - IPCOMP_LZJH = 4 -}; - extern enum_names ipcomp_transformid_names; /* Certificate type values @@ -251,9 +246,6 @@ extern enum_name_t *timer_event_names; enum event_type { EVENT_NULL, /* non-event */ EVENT_REINIT_SECRET, /* Refresh cookie secret */ -#ifdef KLIPS - EVENT_SHUNT_SCAN, /* scan shunt eroutes known to kernel */ -#endif EVENT_SO_DISCARD, /* discard unfinished state object */ EVENT_RETRANSMIT, /* Retransmit packet */ EVENT_SA_REPLACE, /* SA replacement event */ @@ -325,7 +317,7 @@ extern const char *const debug_bit_names[]; #define DBG_EMITTING LELEM(3) /* show encoding of messages */ #define DBG_CONTROL LELEM(4) /* control flow within Pluto */ #define DBG_LIFECYCLE LELEM(5) /* SA lifecycle */ -#define DBG_KLIPS LELEM(6) /* messages to KLIPS */ +#define DBG_KERNEL LELEM(6) /* messages to kernel */ #define DBG_DNS LELEM(7) /* DNS activity */ #define DBG_NATT LELEM(8) /* NAT-T */ #define DBG_OPPO LELEM(9) /* opportunism */ @@ -376,11 +368,6 @@ extern const char *const state_story[]; enum state_kind { STATE_UNDEFINED, /* 0 -- most likely accident */ - /* Opportunism states: see "Opportunistic Encryption" 2.2 */ - - OPPO_ACQUIRE, /* got an ACQUIRE message for this pair */ - OPPO_GW_DISCOVERED, /* got TXT specifying gateway */ - /* IKE states */ STATE_MAIN_R0, diff --git a/src/pluto/crypto.c b/src/pluto/crypto.c index a62e7632d..0684de618 100644 --- a/src/pluto/crypto.c +++ b/src/pluto/crypto.c @@ -1,6 +1,10 @@ /* crypto interfaces + * + * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2007-2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 1998-2001 D. Hugh Redelmeier - * Copyright (C) 2007-2009 Andreas Steffen - 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 @@ -26,10 +30,10 @@ static struct encrypt_desc encrypt_desc_3des = algo_id: OAKLEY_3DES_CBC, algo_next: NULL, - enc_blocksize: DES_BLOCK_SIZE, - keydeflen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keyminlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keymaxlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, + enc_blocksize: DES_BLOCK_SIZE, + keydeflen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, + keyminlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, + keymaxlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, }; #define AES_KEY_MIN_LEN 128 @@ -38,14 +42,14 @@ static struct encrypt_desc encrypt_desc_3des = static struct encrypt_desc encrypt_desc_aes = { - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_AES_CBC, - algo_next: NULL, - - enc_blocksize: AES_BLOCK_SIZE, - keyminlen: AES_KEY_MIN_LEN, - keydeflen: AES_KEY_DEF_LEN, - keymaxlen: AES_KEY_MAX_LEN, + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_AES_CBC, + algo_next: NULL, + + enc_blocksize: AES_BLOCK_SIZE, + keyminlen: AES_KEY_MIN_LEN, + keydeflen: AES_KEY_DEF_LEN, + keymaxlen: AES_KEY_MAX_LEN, }; #define CAMELLIA_KEY_MIN_LEN 128 @@ -54,14 +58,14 @@ static struct encrypt_desc encrypt_desc_aes = static struct encrypt_desc encrypt_desc_camellia = { - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_CAMELLIA_CBC, - algo_next: NULL, - - enc_blocksize: CAMELLIA_BLOCK_SIZE, - keyminlen: CAMELLIA_KEY_MIN_LEN, - keydeflen: CAMELLIA_KEY_DEF_LEN, - keymaxlen: CAMELLIA_KEY_MAX_LEN, + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_CAMELLIA_CBC, + algo_next: NULL, + + enc_blocksize: CAMELLIA_BLOCK_SIZE, + keyminlen: CAMELLIA_KEY_MIN_LEN, + keydeflen: CAMELLIA_KEY_DEF_LEN, + keymaxlen: CAMELLIA_KEY_MAX_LEN, }; #define BLOWFISH_KEY_MIN_LEN 128 @@ -73,10 +77,10 @@ static struct encrypt_desc encrypt_desc_blowfish = algo_id: OAKLEY_BLOWFISH_CBC, algo_next: NULL, - enc_blocksize: BLOWFISH_BLOCK_SIZE, - keyminlen: BLOWFISH_KEY_MIN_LEN, - keydeflen: BLOWFISH_KEY_MIN_LEN, - keymaxlen: BLOWFISH_KEY_MAX_LEN, + enc_blocksize: BLOWFISH_BLOCK_SIZE, + keyminlen: BLOWFISH_KEY_MIN_LEN, + keydeflen: BLOWFISH_KEY_MIN_LEN, + keymaxlen: BLOWFISH_KEY_MAX_LEN, }; #define SERPENT_KEY_MIN_LEN 128 @@ -85,14 +89,14 @@ static struct encrypt_desc encrypt_desc_blowfish = static struct encrypt_desc encrypt_desc_serpent = { - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_SERPENT_CBC, - algo_next: NULL, + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_SERPENT_CBC, + algo_next: NULL, enc_blocksize: SERPENT_BLOCK_SIZE, - keyminlen: SERPENT_KEY_MIN_LEN, - keydeflen: SERPENT_KEY_DEF_LEN, - keymaxlen: SERPENT_KEY_MAX_LEN, + keyminlen: SERPENT_KEY_MIN_LEN, + keydeflen: SERPENT_KEY_DEF_LEN, + keymaxlen: SERPENT_KEY_MAX_LEN, }; #define TWOFISH_KEY_MIN_LEN 128 @@ -101,62 +105,62 @@ static struct encrypt_desc encrypt_desc_serpent = static struct encrypt_desc encrypt_desc_twofish = { - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC, - algo_next: NULL, - - enc_blocksize: TWOFISH_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_TWOFISH_CBC, + algo_next: NULL, + + enc_blocksize: TWOFISH_BLOCK_SIZE, + keydeflen: TWOFISH_KEY_MIN_LEN, + keyminlen: TWOFISH_KEY_DEF_LEN, + keymaxlen: TWOFISH_KEY_MAX_LEN, }; static struct encrypt_desc encrypt_desc_twofish_ssh = { - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC_SSH, - algo_next: NULL, - - enc_blocksize: TWOFISH_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_TWOFISH_CBC_SSH, + algo_next: NULL, + + enc_blocksize: TWOFISH_BLOCK_SIZE, + keydeflen: TWOFISH_KEY_MIN_LEN, + keyminlen: TWOFISH_KEY_DEF_LEN, + keymaxlen: TWOFISH_KEY_MAX_LEN, }; static struct hash_desc hash_desc_md5 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_MD5, - algo_next: NULL, + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_MD5, + algo_next: NULL, hash_digest_size: HASH_SIZE_MD5, }; static struct hash_desc hash_desc_sha1 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA, - algo_next: NULL, + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA, + algo_next: NULL, hash_digest_size: HASH_SIZE_SHA1, }; static struct hash_desc hash_desc_sha2_256 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_256, - algo_next: NULL, + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA2_256, + algo_next: NULL, hash_digest_size: HASH_SIZE_SHA256, }; static struct hash_desc hash_desc_sha2_384 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_384, - algo_next: NULL, + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA2_384, + algo_next: NULL, hash_digest_size: HASH_SIZE_SHA384, }; static struct hash_desc hash_desc_sha2_512 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_512, - algo_next: NULL, + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA2_512, + algo_next: NULL, hash_digest_size: HASH_SIZE_SHA512, }; @@ -518,107 +522,117 @@ signature_scheme_t oakley_to_signature_scheme(int method) } /** + * Table to map IKEv2 encryption algorithms to IKEv1 (or IKEv1 ESP) and back + */ +struct { + encryption_algorithm_t alg; + int oakley; + int esp; +} encr_map[] = { + {ENCR_DES, OAKLEY_DES_CBC, ESP_DES }, + {ENCR_3DES, OAKLEY_3DES_CBC, ESP_3DES }, + {ENCR_RC5, OAKLEY_RC5_R16_B64_CBC, ESP_RC5 }, + {ENCR_IDEA, OAKLEY_IDEA_CBC, ESP_IDEA }, + {ENCR_CAST, OAKLEY_CAST_CBC, ESP_CAST }, + {ENCR_BLOWFISH, OAKLEY_BLOWFISH_CBC, ESP_BLOWFISH }, + {ENCR_AES_CBC, OAKLEY_AES_CBC, ESP_AES }, + {ENCR_CAMELLIA_CBC, OAKLEY_CAMELLIA_CBC, ESP_CAMELLIA }, + {ENCR_SERPENT_CBC, OAKLEY_SERPENT_CBC, ESP_SERPENT }, + {ENCR_TWOFISH_CBC, OAKLEY_TWOFISH_CBC, ESP_TWOFISH }, + {ENCR_NULL, 0, ESP_NULL }, + {ENCR_AES_CTR, 0, ESP_AES_CTR }, + {ENCR_AES_CCM_ICV8, 0, ESP_AES_CCM_8 }, + {ENCR_AES_CCM_ICV12, 0, ESP_AES_CCM_12}, + {ENCR_AES_CCM_ICV16, 0, ESP_AES_CCM_16}, + {ENCR_AES_GCM_ICV8, 0, ESP_AES_GCM_8 }, + {ENCR_AES_GCM_ICV12, 0, ESP_AES_GCM_12}, + {ENCR_AES_GCM_ICV16, 0, ESP_AES_GCM_16}, + {ENCR_NULL_AUTH_AES_GMAC, 0, ESP_AES_GMAC }, +}; + +/** * Converts IKEv2 encryption to IKEv1 encryption algorithm */ int oakley_from_encryption_algorithm(encryption_algorithm_t alg) { - switch (alg) + int i; + for (i = 0; i < countof(encr_map); i++) { - case ENCR_DES: - return OAKLEY_DES_CBC; - case ENCR_3DES: - return OAKLEY_3DES_CBC; - case ENCR_RC5: - return OAKLEY_RC5_R16_B64_CBC; - case ENCR_IDEA: - return OAKLEY_IDEA_CBC; - case ENCR_CAST: - return OAKLEY_CAST_CBC; - case ENCR_BLOWFISH: - return OAKLEY_BLOWFISH_CBC; - case ENCR_AES_CBC: - return OAKLEY_AES_CBC; - case ENCR_CAMELLIA_CBC: - return OAKLEY_CAMELLIA_CBC; - case ENCR_SERPENT_CBC: - return OAKLEY_SERPENT_CBC; - case ENCR_TWOFISH_CBC: - return OAKLEY_TWOFISH_CBC; - default: - return 0; + if (encr_map[i].alg == alg) + { + return encr_map[i].oakley; + } } + return 0; } /** - * Converts IKEv2 integrity to IKEv1 hash algorithm + * Converts IKEv2 encryption to IKEv1 ESP encryption algorithm */ -int oakley_from_integrity_algorithm(integrity_algorithm_t alg) +int esp_from_encryption_algorithm(encryption_algorithm_t alg) { - switch (alg) + int i; + for (i = 0; i < countof(encr_map); i++) { - case AUTH_HMAC_MD5_96: - return OAKLEY_MD5; - case AUTH_HMAC_SHA1_96: - return OAKLEY_SHA; - case AUTH_HMAC_SHA2_256_128: - return OAKLEY_SHA2_256; - case AUTH_HMAC_SHA2_384_192: - return OAKLEY_SHA2_384; - case AUTH_HMAC_SHA2_512_256: - return OAKLEY_SHA2_512; - default: - return 0; + if (encr_map[i].alg == alg) + { + return encr_map[i].esp; + } } + return 0; } /** - * Converts IKEv2 encryption to IKEv1 ESP encryption algorithm + * Converts IKEv1 ESP encryption to IKEv2 algorithm */ -int esp_from_encryption_algorithm(encryption_algorithm_t alg) +encryption_algorithm_t encryption_algorithm_from_esp(int esp) { - switch (alg) + int i; + for (i = 0; i < countof(encr_map); i++) { - case ENCR_DES: - return ESP_DES; - case ENCR_3DES: - return ESP_3DES; - case ENCR_RC5: - return ESP_RC5; - case ENCR_IDEA: - return ESP_IDEA; - case ENCR_CAST: - return ESP_CAST; - case ENCR_BLOWFISH: - return ESP_BLOWFISH; - case ENCR_NULL: - return ESP_NULL; - case ENCR_AES_CBC: - return ESP_AES; - case ENCR_AES_CTR: - return ESP_AES_CTR; - case ENCR_AES_CCM_ICV8: - return ESP_AES_CCM_8; - case ENCR_AES_CCM_ICV12: - return ESP_AES_CCM_12; - case ENCR_AES_CCM_ICV16: - return ESP_AES_CCM_16; - case ENCR_AES_GCM_ICV8: - return ESP_AES_GCM_8; - case ENCR_AES_GCM_ICV12: - return ESP_AES_GCM_12; - case ENCR_AES_GCM_ICV16: - return ESP_AES_GCM_16; - case ENCR_CAMELLIA_CBC: - return ESP_CAMELLIA; - case ENCR_NULL_AUTH_AES_GMAC: - return ESP_AES_GMAC; - case ENCR_SERPENT_CBC: - return ESP_SERPENT; - case ENCR_TWOFISH_CBC: - return ESP_TWOFISH; - default: - return 0; + if (encr_map[i].esp == esp) + { + return encr_map[i].alg; + } + } + return 0; +} + +/** + * Table to map IKEv2 integrity algorithms to IKEv1 (or IKEv1 ESP) and back + */ +struct { + integrity_algorithm_t alg; + int oakley; + int esp; +} auth_map[] = { + {AUTH_HMAC_MD5_96, OAKLEY_MD5, AUTH_ALGORITHM_HMAC_MD5 }, + {AUTH_HMAC_SHA1_96, OAKLEY_SHA, AUTH_ALGORITHM_HMAC_SHA1 }, + {AUTH_HMAC_SHA2_256_96, 0, AUTH_ALGORITHM_HMAC_SHA2_256_96}, + {AUTH_HMAC_SHA2_256_128, OAKLEY_SHA2_256, AUTH_ALGORITHM_HMAC_SHA2_256 }, + {AUTH_HMAC_SHA2_384_192, OAKLEY_SHA2_384, AUTH_ALGORITHM_HMAC_SHA2_384 }, + {AUTH_HMAC_SHA2_512_256, OAKLEY_SHA2_512, AUTH_ALGORITHM_HMAC_SHA2_512 }, + {AUTH_AES_XCBC_96, 0, AUTH_ALGORITHM_AES_XCBC_MAC }, + {AUTH_AES_128_GMAC, 0, AUTH_ALGORITHM_AES_128_GMAC }, + {AUTH_AES_192_GMAC, 0, AUTH_ALGORITHM_AES_192_GMAC }, + {AUTH_AES_256_GMAC, 0, AUTH_ALGORITHM_AES_256_GMAC }, +}; + + +/** + * Converts IKEv2 integrity to IKEv1 hash algorithm + */ +int oakley_from_integrity_algorithm(integrity_algorithm_t alg) +{ + int i; + for (i = 0; i < countof(auth_map); i++) + { + if (auth_map[i].alg == alg) + { + return auth_map[i].oakley; + } } + return 0; } /** @@ -626,29 +640,30 @@ int esp_from_encryption_algorithm(encryption_algorithm_t alg) */ int esp_from_integrity_algorithm(integrity_algorithm_t alg) { - switch (alg) + int i; + for (i = 0; i < countof(auth_map); i++) { - case AUTH_HMAC_MD5_96: - return AUTH_ALGORITHM_HMAC_MD5; - case AUTH_HMAC_SHA1_96: - return AUTH_ALGORITHM_HMAC_SHA1; - case AUTH_AES_XCBC_96: - return AUTH_ALGORITHM_AES_XCBC_MAC; - case AUTH_HMAC_SHA2_256_96: - return AUTH_ALGORITHM_HMAC_SHA2_256_96; - case AUTH_HMAC_SHA2_256_128: - return AUTH_ALGORITHM_HMAC_SHA2_256; - case AUTH_HMAC_SHA2_384_192: - return AUTH_ALGORITHM_HMAC_SHA2_384; - case AUTH_HMAC_SHA2_512_256: - return AUTH_ALGORITHM_HMAC_SHA2_512; - case AUTH_AES_128_GMAC: - return AUTH_ALGORITHM_AES_128_GMAC; - case AUTH_AES_192_GMAC: - return AUTH_ALGORITHM_AES_192_GMAC; - case AUTH_AES_256_GMAC: - return AUTH_ALGORITHM_AES_256_GMAC; - default: - return 0; + if (auth_map[i].alg == alg) + { + return auth_map[i].esp; + } } + return 0; } + +/** + * Converts IKEv1 ESP authentication to IKEv2 integrity algorithm + */ +integrity_algorithm_t integrity_algorithm_from_esp(int esp) +{ + int i; + for (i = 0; i < countof(auth_map); i++) + { + if (auth_map[i].esp == esp) + { + return auth_map[i].alg; + } + } + return 0; +} + diff --git a/src/pluto/crypto.h b/src/pluto/crypto.h index 019ba5764..16ad12780 100644 --- a/src/pluto/crypto.h +++ b/src/pluto/crypto.h @@ -1,4 +1,9 @@ /* crypto interfaces + * + * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 1998, 1999 D. Hugh Redelmeier. * * This program is free software; you can redistribute it and/or modify it @@ -54,4 +59,6 @@ extern int oakley_from_encryption_algorithm(encryption_algorithm_t alg); extern int oakley_from_integrity_algorithm(integrity_algorithm_t alg); extern int esp_from_encryption_algorithm(encryption_algorithm_t alg); extern int esp_from_integrity_algorithm(integrity_algorithm_t alg); +extern encryption_algorithm_t encryption_algorithm_from_esp(int esp); +extern integrity_algorithm_t integrity_algorithm_from_esp(int esp); diff --git a/src/pluto/defs.h b/src/pluto/defs.h index 8491f4ae8..532652e5b 100644 --- a/src/pluto/defs.h +++ b/src/pluto/defs.h @@ -21,12 +21,6 @@ #include <chunk.h> -#ifdef KLIPS -# define USED_BY_KLIPS /* ignore */ -#else -# define USED_BY_KLIPS UNUSED -#endif - #ifdef DEBUG # define USED_BY_DEBUG /* ignore */ #else @@ -66,15 +60,6 @@ extern const char* check_expiry(time_t expiration_date, #define MAX_PROMPT_PASS_TRIALS 5 #define PROMPT_PASS_LEN 64 -/* struct used to prompt for a secret passphrase - * from a console with file descriptor fd - */ -typedef struct { - char secret[PROMPT_PASS_LEN+1]; - bool prompt; - int fd; -} prompt_pass_t; - /* filter eliminating the directory entries '.' and '..' */ typedef struct dirent dirent_t; extern int file_select(const dirent_t *entry); diff --git a/src/pluto/demux.c b/src/pluto/demux.c index 617353c6c..0590a3585 100644 --- a/src/pluto/demux.c +++ b/src/pluto/demux.c @@ -1782,7 +1782,7 @@ process_packet(struct msg_digest **mdp) * the last phase 1 block, not the last block sent. */ { - size_t crypter_block_size; + size_t crypter_block_size, crypter_iv_size; encryption_algorithm_t enc_alg; crypter_t *crypter; chunk_t data, iv; @@ -1791,6 +1791,7 @@ process_packet(struct msg_digest **mdp) enc_alg = oakley_to_encryption_algorithm(st->st_oakley.encrypt); crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, st->st_enc_key.len); crypter_block_size = crypter->get_block_size(crypter); + crypter_iv_size = crypter->get_iv_size(crypter); if (pbs_left(&md->message_pbs) % crypter_block_size != 0) { @@ -1817,17 +1818,17 @@ process_packet(struct msg_digest **mdp) } /* form iv by truncation */ - st->st_new_iv_len = crypter_block_size; + st->st_new_iv_len = crypter_iv_size; iv = chunk_create(st->st_new_iv, st->st_new_iv_len); - new_iv = alloca(crypter_block_size); - memcpy(new_iv, data.ptr + data.len - crypter_block_size, - crypter_block_size); + new_iv = alloca(crypter_iv_size); + memcpy(new_iv, data.ptr + data.len - crypter_iv_size, + crypter_iv_size); crypter->set_key(crypter, st->st_enc_key); crypter->decrypt(crypter, data, iv, NULL); crypter->destroy(crypter); - memcpy(st->st_new_iv, new_iv, crypter_block_size); + memcpy(st->st_new_iv, new_iv, crypter_iv_size); if (restore_iv) { memcpy(st->st_new_iv, new_iv, new_iv_len); @@ -2307,7 +2308,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result) /* tell whack and log of progress */ { - const char *story = state_story[st->st_state - STATE_MAIN_R0]; + const char *story = state_story[st->st_state]; enum rc_type w = RC_NEW_STATE + st->st_state; char sadetails[128]; diff --git a/src/pluto/event_queue.c b/src/pluto/event_queue.c new file mode 100644 index 000000000..55d064f26 --- /dev/null +++ b/src/pluto/event_queue.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2010 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 <unistd.h> +#include <fcntl.h> + +#include "event_queue.h" + +#include <debug.h> +#include <threading/mutex.h> +#include <utils/linked_list.h> + +typedef struct private_event_queue_t private_event_queue_t; + +/** + * Private data of event_queue_t class. + */ +struct private_event_queue_t { + /** + * Public event_queue_t interface. + */ + event_queue_t public; + + /** + * List of queued events (event_t*). + */ + linked_list_t *events; + + /** + * Mutex for event list. + */ + mutex_t *mutex; + + /** + * Read end of the notification pipe. + */ + int read_fd; + + /** + * Write end of the notification pipe. + */ + int write_fd; + +}; + +typedef struct event_t event_t; + +struct event_t { + /** + * Callback function. + */ + void (*callback)(void *data); + + /** + * Data to supply to the callback. + */ + void *data; + + /** + * Cleanup function. + */ + void (*cleanup)(void *data); +}; + +static event_t *event_create(void (*callback)(void *data), void *data, + void (*cleanup)(void *data)) +{ + event_t *this; + INIT(this, + .callback = callback, + .data = data, + .cleanup = cleanup, + ); + return this; +} + +static void event_destroy(event_t *this) +{ + if (this->cleanup) + { + this->cleanup(this->data); + } + free(this); +} + +METHOD(event_queue_t, get_event_fd, int, + private_event_queue_t *this) +{ + return this->read_fd; +} + +METHOD(event_queue_t, handle, void, + private_event_queue_t *this) +{ + char buf[10]; + linked_list_t *events; + event_t *event; + this->mutex->lock(this->mutex); + /* flush pipe */ + while (read(this->read_fd, &buf, sizeof(buf)) == sizeof(buf)); + /* replace the list, so we can unlock the mutex while executing the jobs */ + events = this->events; + this->events = linked_list_create(); + this->mutex->unlock(this->mutex); + + while (events->remove_first(events, (void**)&event) == SUCCESS) + { + event->callback(event->data); + event_destroy(event); + } + events->destroy(events); +} + +METHOD(event_queue_t, queue, void, + private_event_queue_t *this, void (*callback)(void *data), void *data, + void (*cleanup)(void *data)) +{ + event_t *event = event_create(callback, data, cleanup); + char c = 0; + this->mutex->lock(this->mutex); + this->events->insert_last(this->events, event); + ignore_result(write(this->write_fd, &c, 1)); + this->mutex->unlock(this->mutex); +} + +METHOD(event_queue_t, destroy, void, + private_event_queue_t *this) +{ + this->mutex->lock(this->mutex); + this->events->destroy_function(this->events, (void*)event_destroy); + this->mutex->unlock(this->mutex); + this->mutex->destroy(this->mutex); + close(this->read_fd); + close(this->write_fd); + free(this); +} + +bool set_nonblock(int socket) +{ + int flags = fcntl(socket, F_GETFL); + return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1; +} + +bool set_cloexec(int socket) +{ + int flags = fcntl(socket, F_GETFD); + return flags != -1 && fcntl(socket, F_SETFD, flags | FD_CLOEXEC) != -1; +} + +/* + * Described in header. + */ +event_queue_t *event_queue_create() +{ + private_event_queue_t *this; + int fd[2]; + + INIT(this, + .public = { + .get_event_fd = _get_event_fd, + .handle = _handle, + .queue = _queue, + .destroy = _destroy, + }, + .events = linked_list_create(), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + + if (pipe(fd) == -1 || + !set_nonblock(fd[0]) || !set_cloexec(fd[0]) || + !set_nonblock(fd[1]) || !set_cloexec(fd[1])) + { + DBG1(DBG_JOB, "failed to create pipe for job queue"); + _destroy(this); + return NULL; + } + + this->read_fd = fd[0]; + this->write_fd = fd[1]; + + return &this->public; +} + diff --git a/src/pluto/event_queue.h b/src/pluto/event_queue.h new file mode 100644 index 000000000..343729e25 --- /dev/null +++ b/src/pluto/event_queue.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 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 event_queue event_queue + * @{ @ingroup pluto + */ + +#ifndef EVENT_QUEUE_H_ +#define EVENT_QUEUE_H_ + +typedef struct event_queue_t event_queue_t; + +/** + * The event queue facility can be used to synchronize thread-pool threads + * with the pluto main thread. That is, all queued callbacks are executed + * asynchronously by the pluto main thread. + */ +struct event_queue_t { + + /** + * Returns the file descriptor used to notify the main thread. + * + * @return fd to use in the main thread + */ + int (*get_event_fd) (event_queue_t *this); + + /** + * Handle all queued events. + */ + void (*handle) (event_queue_t *this); + + /** + * Add an event to the queue. + * + * @param callback callback function to add to the queue + * @param data data supplied to the callback function + * @param cleanup optional cleanup function + */ + void (*queue) (event_queue_t *this, void (*callback)(void *data), + void *data, void (*cleanup)(void *data)); + + /** + * Destroy this instance. + */ + void (*destroy) (event_queue_t *this); + +}; + +/** + * Create the event queue. + * + * @return created object + */ +event_queue_t *event_queue_create(); + +#endif /** EVENT_QUEUE_H_ @}*/ diff --git a/src/pluto/ike_alg.c b/src/pluto/ike_alg.c index 7521dd33b..08353907e 100644 --- a/src/pluto/ike_alg.c +++ b/src/pluto/ike_alg.c @@ -194,18 +194,16 @@ struct db_context *ike_alg_db_new(connection_t *c, lset_t policy) if (policy & POLICY_PUBKEY) { - int auth_method = 0; - size_t key_size = 0; + int auth_method = 0, key_size = 0; key_type_t key_type = KEY_ANY; - if (c->spd.this.cert) { certificate_t *certificate = c->spd.this.cert->cert; public_key_t *key = certificate->get_public_key(certificate); if (key == NULL) - { + { plog("ike alg: unable to retrieve my public key"); continue; } @@ -233,13 +231,13 @@ struct db_context *ike_alg_db_new(connection_t *c, lset_t policy) case KEY_ECDSA: switch (key_size) { - case 32: + case 256: auth_method = OAKLEY_ECDSA_256; break; - case 48: + case 384: auth_method = OAKLEY_ECDSA_384; break; - case 66: + case 521: auth_method = OAKLEY_ECDSA_521; break; default: diff --git a/src/pluto/ipsec.secrets.5 b/src/pluto/ipsec.secrets.5 deleted file mode 100644 index 6c39f86e1..000000000 --- a/src/pluto/ipsec.secrets.5 +++ /dev/null @@ -1,175 +0,0 @@ -.TH IPSEC.SECRETS 5 "2010-05-30" "4.4.1rc3" "strongSwan" -.SH NAME -ipsec.secrets \- secrets for IKE/IPsec authentication -.SH DESCRIPTION -The file \fIipsec.secrets\fP holds a table of secrets. -These secrets are used by the strongSwan Internet Key Exchange (IKE) daemons -pluto (IKEv1) and charon (IKEv2) to authenticate other hosts. -.LP -It is vital that these secrets be protected. The file should be owned -by the super-user, -and its permissions should be set to block all access by others. -.LP -The file is a sequence of entries and include directives. -Here is an example. -.LP -.RS -.nf -# /etc/ipsec.secrets - strongSwan IPsec secrets file -192.168.0.1 %any : PSK "v+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL" - -: RSA moonKey.pem - -alice@strongswan.org : EAP "x3.dEhgN" - -: XAUTH carol "4iChxLT3" - -: XAUTH dave "ryftzG4A" - -# get secrets from other files -include ipsec.*.secrets -.fi -.RE -.LP -Each entry in the file is a list of optional ID selectors, followed by a secret. -The two parts are separated by a colon (\fB:\fP) that is surrounded -by whitespace. If no ID selectors are specified the line must start with a -colon. -.LP -A selector is an IP address, a Fully Qualified Domain Name, user@FQDN, -\fB%any\fP or \fB%any6\fP (other kinds may come). An IP address may be written -in the familiar dotted quad form or as a domain name to be looked up -when the file is loaded. -In many cases it is a bad idea to use domain names because -the name server may not be running or may be insecure. To denote a -Fully Qualified Domain Name (as opposed to an IP address denoted by -its domain name), precede the name with an at sign (\fB@\fP). -.LP -Matching IDs with selectors is fairly straightforward: they have to be -equal. In the case of a ``Road Warrior'' connection, if an equal -match is not found for the Peer's ID, and it is in the form of an IP -address, a selector of \fB%any\fP will match the peer's IP address if IPV4 -and \fB%any6\fP will match a the peer's IP address if IPV6. -Currently, the obsolete notation \fB0.0.0.0\fP may be used in place of -\fB%any\fP. -.LP -In IKEv1 an additional complexity -arises in the case of authentication by preshared secret: the -responder will need to look up the secret before the Peer's ID payload has -been decoded, so the ID used will be the IP address. -.LP -To authenticate a connection between two hosts, the entry that most -specifically matches the host and peer IDs is used. An entry with no -selectors will match any host and peer. More specifically, an entry with one -selector will match a host and peer if the selector matches the host's ID (the -peer isn't considered). Still more specifically, an entry with multiple -selectors will match a host and peer if the host ID and peer ID each match one -of the selectors. If the key is for an asymmetric authentication technique -(i.e. a public key system such as RSA), an entry with multiple selectors will -match a host and peer even if only the host ID matches a selector (it is -presumed that the selectors are all identities of the host). -It is acceptable for two entries to be the best match as -long as they agree about the secret or private key. -.LP -Authentication by preshared secret requires that both systems find the -identical secret (the secret is not actually transmitted by the IKE -protocol). If both the host and peer appear in the selector list, the -same entry will be suitable for both systems so verbatim copying -between systems can be used. This naturally extends to larger groups -sharing the same secret. Thus multiple-selector entries are best for PSK -authentication. -.LP -Authentication by public key systems such as RSA requires that each host -have its own private key. A host could reasonably use a different private keys -for different interfaces and for different peers. But it would not -be normal to share entries between systems. Thus thus no-selector and -one-selector forms of entry often make sense for public key authentication. -.LP -The key part of an entry must start with a token indicating the kind of -key. The following types of secrets are currently supported: -.TP -.B PSK -defines a pre-shared key -.TP -.B RSA -defines an RSA private key -.TP -.B ECDSA -defines an ECDSA private key -.TP -.B EAP -defines EAP credentials -.TP -.B XAUTH -defines XAUTH credentials -.TP -.B PIN -defines a smartcard PIN -.LP -Details on each type of secret are given below. -.LP -Whitespace at the end of a line is ignored. At the start of a line or -after whitespace, \fB#\fP and the following text up to the end of the -line is treated as a comment. -.LP -An include directive causes the contents of the named file to be processed -before continuing with the current file. The filename is subject to -``globbing'' as in \fIsh\fP(1), so every file with a matching name -is processed. Includes may be nested to a modest -depth (10, currently). If the filename doesn't start with a \fB/\fP, the -directory containing the current file is prepended to the name. The -include directive is a line that starts with the word \fBinclude\fP, -followed by whitespace, followed by the filename (which must not contain -whitespace). -.SS TYPES OF SECRETS -.TP -.B [ <selectors> ] : PSK <secret> -A preshared secret is most conveniently represented as a sequence of -characters, delimited by double-quote characters (\fB"\fP). -The sequence cannot contain a newline or double-quote. -Strictly speaking, the secret is actually the sequence -of bytes that is used in the file to represent the sequence of -characters (excluding the delimiters). -.TP -.B [ <selectors> ] : RSA <private key file> [ <passphrase> | %prompt ] -.TQ -.B [ <selectors> ] : ECDSA <private key file> [ <passphrase> | %prompt ] -For the private key file both absolute paths or paths relative to -\fI/etc/ipsec.d/private\fP are accepted. If the private key file is -encrypted, the \fIpassphrase\fP must be defined. Instead of a passphrase -.B %prompt -can be used which then causes the daemons to ask the user for the password -whenever it is required to decrypt the key. -.TP -.B <user id> : EAP <secret> -As with \fBPSK\fP secrets the \fIsecret\fP is a sequence of characters, -delimited by double-quote characters (\fB"\fP). -.br -\fBEAP\fP secrets are IKEv2 only. -.TP -.B : XAUTH <username> <password> -\fBXAUTH\fP secrets are IKEv1 only. -.TP -.B : PIN <smartcard selector> <pin code> | %prompt -The format -.B "%smartcard[<slot nr>[:<key id>]]" -is used to specify the smartcard selector (e.g. %smartcard1:50). For IKEv1, -instead of specifying the pin code statically, -.B %prompt -can be specified, which causes the pluto daemon to ask the user for the pin -code. -.LP - -.SH FILES -/etc/ipsec.secrets -.SH SEE ALSO -\fIipsec.conf\fP(5), -\fIipsec\fP(8) -.br -.SH HISTORY -Originally written for the FreeS/WAN project by D. Hugh Redelmeier. -Updated and extended for the strongSwan project <http://www.strongswan.org> by -Tobias Brunner and Andreas Steffen. -.SH BUGS -If an ID is \fB0.0.0.0\fP, it will match \fB%any\fP; -if it is \fB0::0\fP, it will match \fB%any6\fP. diff --git a/src/pluto/ipsec.secrets.5.in b/src/pluto/ipsec.secrets.5.in deleted file mode 100644 index adb915e4d..000000000 --- a/src/pluto/ipsec.secrets.5.in +++ /dev/null @@ -1,175 +0,0 @@ -.TH IPSEC.SECRETS 5 "2010-05-30" "@IPSEC_VERSION@" "strongSwan" -.SH NAME -ipsec.secrets \- secrets for IKE/IPsec authentication -.SH DESCRIPTION -The file \fIipsec.secrets\fP holds a table of secrets. -These secrets are used by the strongSwan Internet Key Exchange (IKE) daemons -pluto (IKEv1) and charon (IKEv2) to authenticate other hosts. -.LP -It is vital that these secrets be protected. The file should be owned -by the super-user, -and its permissions should be set to block all access by others. -.LP -The file is a sequence of entries and include directives. -Here is an example. -.LP -.RS -.nf -# /etc/ipsec.secrets - strongSwan IPsec secrets file -192.168.0.1 %any : PSK "v+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL" - -: RSA moonKey.pem - -alice@strongswan.org : EAP "x3.dEhgN" - -: XAUTH carol "4iChxLT3" - -: XAUTH dave "ryftzG4A" - -# get secrets from other files -include ipsec.*.secrets -.fi -.RE -.LP -Each entry in the file is a list of optional ID selectors, followed by a secret. -The two parts are separated by a colon (\fB:\fP) that is surrounded -by whitespace. If no ID selectors are specified the line must start with a -colon. -.LP -A selector is an IP address, a Fully Qualified Domain Name, user@FQDN, -\fB%any\fP or \fB%any6\fP (other kinds may come). An IP address may be written -in the familiar dotted quad form or as a domain name to be looked up -when the file is loaded. -In many cases it is a bad idea to use domain names because -the name server may not be running or may be insecure. To denote a -Fully Qualified Domain Name (as opposed to an IP address denoted by -its domain name), precede the name with an at sign (\fB@\fP). -.LP -Matching IDs with selectors is fairly straightforward: they have to be -equal. In the case of a ``Road Warrior'' connection, if an equal -match is not found for the Peer's ID, and it is in the form of an IP -address, a selector of \fB%any\fP will match the peer's IP address if IPV4 -and \fB%any6\fP will match a the peer's IP address if IPV6. -Currently, the obsolete notation \fB0.0.0.0\fP may be used in place of -\fB%any\fP. -.LP -In IKEv1 an additional complexity -arises in the case of authentication by preshared secret: the -responder will need to look up the secret before the Peer's ID payload has -been decoded, so the ID used will be the IP address. -.LP -To authenticate a connection between two hosts, the entry that most -specifically matches the host and peer IDs is used. An entry with no -selectors will match any host and peer. More specifically, an entry with one -selector will match a host and peer if the selector matches the host's ID (the -peer isn't considered). Still more specifically, an entry with multiple -selectors will match a host and peer if the host ID and peer ID each match one -of the selectors. If the key is for an asymmetric authentication technique -(i.e. a public key system such as RSA), an entry with multiple selectors will -match a host and peer even if only the host ID matches a selector (it is -presumed that the selectors are all identities of the host). -It is acceptable for two entries to be the best match as -long as they agree about the secret or private key. -.LP -Authentication by preshared secret requires that both systems find the -identical secret (the secret is not actually transmitted by the IKE -protocol). If both the host and peer appear in the selector list, the -same entry will be suitable for both systems so verbatim copying -between systems can be used. This naturally extends to larger groups -sharing the same secret. Thus multiple-selector entries are best for PSK -authentication. -.LP -Authentication by public key systems such as RSA requires that each host -have its own private key. A host could reasonably use a different private keys -for different interfaces and for different peers. But it would not -be normal to share entries between systems. Thus thus no-selector and -one-selector forms of entry often make sense for public key authentication. -.LP -The key part of an entry must start with a token indicating the kind of -key. The following types of secrets are currently supported: -.TP -.B PSK -defines a pre-shared key -.TP -.B RSA -defines an RSA private key -.TP -.B ECDSA -defines an ECDSA private key -.TP -.B EAP -defines EAP credentials -.TP -.B XAUTH -defines XAUTH credentials -.TP -.B PIN -defines a smartcard PIN -.LP -Details on each type of secret are given below. -.LP -Whitespace at the end of a line is ignored. At the start of a line or -after whitespace, \fB#\fP and the following text up to the end of the -line is treated as a comment. -.LP -An include directive causes the contents of the named file to be processed -before continuing with the current file. The filename is subject to -``globbing'' as in \fIsh\fP(1), so every file with a matching name -is processed. Includes may be nested to a modest -depth (10, currently). If the filename doesn't start with a \fB/\fP, the -directory containing the current file is prepended to the name. The -include directive is a line that starts with the word \fBinclude\fP, -followed by whitespace, followed by the filename (which must not contain -whitespace). -.SS TYPES OF SECRETS -.TP -.B [ <selectors> ] : PSK <secret> -A preshared secret is most conveniently represented as a sequence of -characters, delimited by double-quote characters (\fB"\fP). -The sequence cannot contain a newline or double-quote. -Strictly speaking, the secret is actually the sequence -of bytes that is used in the file to represent the sequence of -characters (excluding the delimiters). -.TP -.B [ <selectors> ] : RSA <private key file> [ <passphrase> | %prompt ] -.TQ -.B [ <selectors> ] : ECDSA <private key file> [ <passphrase> | %prompt ] -For the private key file both absolute paths or paths relative to -\fI/etc/ipsec.d/private\fP are accepted. If the private key file is -encrypted, the \fIpassphrase\fP must be defined. Instead of a passphrase -.B %prompt -can be used which then causes the daemons to ask the user for the password -whenever it is required to decrypt the key. -.TP -.B <user id> : EAP <secret> -As with \fBPSK\fP secrets the \fIsecret\fP is a sequence of characters, -delimited by double-quote characters (\fB"\fP). -.br -\fBEAP\fP secrets are IKEv2 only. -.TP -.B : XAUTH <username> <password> -\fBXAUTH\fP secrets are IKEv1 only. -.TP -.B : PIN <smartcard selector> <pin code> | %prompt -The format -.B "%smartcard[<slot nr>[:<key id>]]" -is used to specify the smartcard selector (e.g. %smartcard1:50). For IKEv1, -instead of specifying the pin code statically, -.B %prompt -can be specified, which causes the pluto daemon to ask the user for the pin -code. -.LP - -.SH FILES -/etc/ipsec.secrets -.SH SEE ALSO -\fIipsec.conf\fP(5), -\fIipsec\fP(8) -.br -.SH HISTORY -Originally written for the FreeS/WAN project by D. Hugh Redelmeier. -Updated and extended for the strongSwan project <http://www.strongswan.org> by -Tobias Brunner and Andreas Steffen. -.SH BUGS -If an ID is \fB0.0.0.0\fP, it will match \fB%any\fP; -if it is \fB0::0\fP, it will match \fB%any6\fP. diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c index 4a6a7c872..7ec547b0c 100644 --- a/src/pluto/ipsec_doi.c +++ b/src/pluto/ipsec_doi.c @@ -1753,7 +1753,7 @@ bool encrypt_message(pb_stream *pbs, struct state *st) size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr); chunk_t data, iv; char *new_iv; - size_t crypter_block_size; + size_t crypter_block_size, crypter_iv_size; encryption_algorithm_t enc_alg; crypter_t *crypter; @@ -1761,6 +1761,7 @@ bool encrypt_message(pb_stream *pbs, struct state *st) enc_alg = oakley_to_encryption_algorithm(st->st_oakley.encrypt); crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, st->st_enc_key.len); crypter_block_size = crypter->get_block_size(crypter); + crypter_iv_size = crypter->get_iv_size(crypter); /* Pad up to multiple of encryption blocksize. * See the description associated with the definition of @@ -1781,15 +1782,15 @@ bool encrypt_message(pb_stream *pbs, struct state *st) data = chunk_create(enc_start, enc_len); /* form iv by truncation */ - st->st_new_iv_len = crypter_block_size; + st->st_new_iv_len = crypter_iv_size; iv = chunk_create(st->st_new_iv, st->st_new_iv_len); crypter->set_key(crypter, st->st_enc_key); crypter->encrypt(crypter, data, iv, NULL); crypter->destroy(crypter); - new_iv = data.ptr + data.len - crypter_block_size; - memcpy(st->st_new_iv, new_iv, crypter_block_size); + new_iv = data.ptr + data.len - crypter_iv_size; + memcpy(st->st_new_iv, new_iv, crypter_iv_size); update_iv(st); DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len); close_message(pbs); diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c index dd7ed8893..e57822ffb 100644 --- a/src/pluto/kernel.c +++ b/src/pluto/kernel.c @@ -1,7 +1,11 @@ /* routines that interface with the kernel's IPsec mechanism - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil + * + * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * + * Copyright (C) 1998-2002 D. Hugh Redelmeier + * Copyright (C) 1997 Angelos D. Keromytis * * 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 @@ -32,16 +36,16 @@ #include <freeswan.h> #include <library.h> +#include <hydra.h> #include <crypto/rngs/rng.h> +#include <kernel/kernel_listener.h> -#ifdef KLIPS #include <signal.h> #include <sys/time.h> /* for select(2) */ #include <sys/types.h> /* for select(2) */ #include <pfkeyv2.h> #include <pfkey.h> #include "kameipsec.h" -#endif /* KLIPS */ #include "constants.h" #include "defs.h" @@ -49,28 +53,21 @@ #include "state.h" #include "timer.h" #include "kernel.h" -#include "kernel_netlink.h" #include "kernel_pfkey.h" -#include "kernel_noklips.h" #include "log.h" #include "ca.h" #include "server.h" #include "whack.h" /* for RC_LOG_SERIOUS */ #include "keys.h" +#include "crypto.h" #include "nat_traversal.h" #include "alg_info.h" #include "kernel_alg.h" +#include "pluto.h" bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */ -/* How far can IPsec messages arrive out of order before the anti-replay - * logic loses track and swats them? 64 is the best KLIPS can do. - * And 32 is the best XFRM can do... - */ -#define REPLAY_WINDOW 64 -#define REPLAY_WINDOW_XFRM 32 - /* test if the routes required for two different connections agree * It is assumed that the destination subnets agree; we are only * testing that the interfaces and nexthops match. @@ -78,282 +75,115 @@ bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */ #define routes_agree(c, d) ((c)->interface == (d)->interface \ && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop)) -#ifndef KLIPS - -bool no_klips = TRUE; /* don't actually use KLIPS */ - -#else /* !KLIPS */ - -/* bare (connectionless) shunt (eroute) table - * - * Bare shunts are those that don't "belong" to a connection. - * This happens because some %trapped traffic hasn't yet or cannot be - * assigned to a connection. The usual reason is that we cannot discover - * the peer SG. Another is that even when the peer has been discovered, - * it may be that no connection matches all the particulars. - * We record them so that, with scanning, we can discover - * which %holds are news and which others should expire. - */ +/* forward declaration */ +static bool shunt_eroute(connection_t *c, struct spd_route *sr, + enum routing_t rt_kind, unsigned int op, + const char *opname); -#define SHUNT_SCAN_INTERVAL (60 * 2) /* time between scans of eroutes */ +static void set_text_said(char *text_said, const ip_address *dst, + ipsec_spi_t spi, int proto); -/* SHUNT_PATIENCE only has resolution down to a multiple of the sample rate, - * SHUNT_SCAN_INTERVAL. - * By making SHUNT_PATIENCE an odd multiple of half of SHUNT_SCAN_INTERVAL, - * we minimize the effects of jitter. +/** + * Default IPsec SA config (e.g. to install trap policies). */ -#define SHUNT_PATIENCE (SHUNT_SCAN_INTERVAL * 15 / 2) /* inactivity timeout */ - -struct bare_shunt { - policy_prio_t policy_prio; - ip_subnet ours; - ip_subnet his; - ip_said said; - int transport_proto; - unsigned long count; - time_t last_activity; - char *why; - struct bare_shunt *next; +static ipsec_sa_cfg_t null_ipsec_sa = { + .mode = MODE_TRANSPORT, + .esp = { + .use = TRUE, + }, }; -static struct bare_shunt *bare_shunts = NULL; - -#ifdef DEBUG -static void DBG_bare_shunt(const char *op, const struct bare_shunt *bs) +/** + * Helper function that converts an ip_subnet to a traffic_selector_t. + */ +static traffic_selector_t *traffic_selector_from_subnet(const ip_subnet *client, + const u_int8_t proto) { - DBG(DBG_KLIPS, - { - int ourport = ntohs(portof(&(bs)->ours.addr)); - int hisport = ntohs(portof(&(bs)->his.addr)); - char ourst[SUBNETTOT_BUF]; - char hist[SUBNETTOT_BUF]; - char sat[SATOT_BUF]; - char prio[POLICY_PRIO_BUF]; - - subnettot(&(bs)->ours, 0, ourst, sizeof(ourst)); - subnettot(&(bs)->his, 0, hist, sizeof(hist)); - satot(&(bs)->said, 0, sat, sizeof(sat)); - fmt_policy_prio(bs->policy_prio, prio); - DBG_log("%s bare shunt %p %s:%d -> %s:%d => %s:%d %s %s" - , op, (const void *)(bs), ourst, ourport, hist, hisport - , sat, (bs)->transport_proto, prio, (bs)->why); - }); + traffic_selector_t *ts; + host_t *net; + net = host_create_from_sockaddr((sockaddr_t*)&client->addr); + ts = traffic_selector_create_from_subnet(net, client->maskbits, proto, + net->get_port(net)); + return ts; } -#else /* !DEBUG */ -#define DBG_bare_shunt(op, bs) {} -#endif /* !DEBUG */ -/* The orphaned_holds table records %holds for which we - * scan_proc_shunts found no representation of in any connection. - * The corresponding ACQUIRE message might have been lost. +/** + * Helper function that converts a traffic_selector_t to an ip_subnet. */ -struct eroute_info *orphaned_holds = NULL; - -/* forward declaration */ -static bool shunt_eroute(connection_t *c, struct spd_route *sr, - enum routing_t rt_kind, unsigned int op, - const char *opname); - -static void set_text_said(char *text_said, const ip_address *dst, - ipsec_spi_t spi, int proto); - -bool no_klips = FALSE; /* don't actually use KLIPS */ +static ip_subnet subnet_from_traffic_selector(traffic_selector_t *ts) +{ + ip_subnet subnet; + host_t *net; + u_int8_t mask; + ts->to_subnet(ts, &net, &mask); + subnet.addr = *(ip_address*)net->get_sockaddr(net); + subnet.maskbits = mask; + net->destroy(net); + return subnet; +} -static const struct pfkey_proto_info null_proto_info[2] = { - { - proto: IPPROTO_ESP, - encapsulation: ENCAPSULATION_MODE_TRANSPORT, - reqid: 0 - }, - { - proto: 0, - encapsulation: 0, - reqid: 0 - } -}; void record_and_initiate_opportunistic(const ip_subnet *ours, const ip_subnet *his, int transport_proto, const char *why) { + ip_address src, dst; passert(samesubnettype(ours, his)); - /* Add to bare shunt list. - * We need to do this because the shunt was installed by KLIPS - * which can't do this itself. - */ - { - struct bare_shunt *bs = malloc_thing(struct bare_shunt); - - bs->why = clone_str(why); - bs->ours = *ours; - bs->his = *his; - bs->transport_proto = transport_proto; - bs->policy_prio = BOTTOM_PRIO; - - bs->said.proto = SA_INT; - bs->said.spi = htonl(SPI_HOLD); - bs->said.dst = *aftoinfo(subnettypeof(ours))->any; - - bs->count = 0; - bs->last_activity = now(); - - bs->next = bare_shunts; - bare_shunts = bs; - DBG_bare_shunt("add", bs); - } - /* actually initiate opportunism */ - { - ip_address src, dst; - - networkof(ours, &src); - networkof(his, &dst); - initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD); - } - - /* if present, remove from orphaned_holds list. - * NOTE: we do this last in case ours or his is a pointer into a member. - */ - { - struct eroute_info **pp, *p; - - for (pp = &orphaned_holds; (p = *pp) != NULL; pp = &p->next) - { - if (samesubnet(ours, &p->ours) - && samesubnet(his, &p->his) - && transport_proto == p->transport_proto - && portof(&ours->addr) == portof(&p->ours.addr) - && portof(&his->addr) == portof(&p->his.addr)) - { - *pp = p->next; - free(p); - break; - } - } - } -} - -#endif /* KLIPS */ - -static unsigned get_proto_reqid(unsigned base, int proto) -{ - switch (proto) - { - default: - case IPPROTO_COMP: - base++; - /* fall through */ - case IPPROTO_ESP: - base++; - /* fall through */ - case IPPROTO_AH: - break; - } - - return base; + networkof(ours, &src); + networkof(his, &dst); + initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD); } /* Generate Unique SPI numbers. * - * The specs say that the number must not be less than IPSEC_DOI_SPI_MIN. - * Pluto generates numbers not less than IPSEC_DOI_SPI_OUR_MIN, - * reserving numbers in between for manual keying (but we cannot so - * restrict numbers generated by our peer). - * XXX This should be replaced by a call to the kernel when - * XXX we get an API. * The returned SPI is in network byte order. - * We use a random number as the initial SPI so that there is - * a good chance that different Pluto instances will choose - * different SPIs. This is good for two reasons. - * - the keying material for the initiator and responder only - * differs if the SPIs differ. - * - if Pluto is restarted, it would otherwise recycle the SPI - * numbers and confuse everything. When the kernel generates - * SPIs, this will no longer matter. - * We then allocate numbers sequentially. Thus we don't have to - * check if the number was previously used (assuming that no - * SPI lives longer than 4G of its successors). */ ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, bool tunnel) { - static ipsec_spi_t spi = 0; /* host order, so not returned directly! */ - char text_said[SATOT_BUF]; - rng_t *rng; + host_t *host_src, *host_dst; + u_int32_t spi; - set_text_said(text_said, &sr->this.host_addr, 0, proto); + host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); + host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); - if (kernel_ops->get_spi) + if (hydra->kernel_interface->get_spi(hydra->kernel_interface, host_src, + host_dst, proto, sr->reqid, &spi) != SUCCESS) { - return kernel_ops->get_spi(&sr->that.host_addr - , &sr->this.host_addr, proto, tunnel - , get_proto_reqid(sr->reqid, proto) - , IPSEC_DOI_SPI_OUR_MIN, 0xffffffff - , text_said); + spi = 0; } - spi++; - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - while (spi < IPSEC_DOI_SPI_OUR_MIN || spi == ntohl(avoid)) - { - rng->get_bytes(rng, sizeof(spi), (u_char *)&spi); - } - rng->destroy(rng); - DBG(DBG_CONTROL, - { - ipsec_spi_t spi_net = htonl(spi); - - DBG_dump("generate SPI:", (u_char *)&spi_net, sizeof(spi_net)); - }); + host_src->destroy(host_src); + host_dst->destroy(host_dst); - return htonl(spi); + return spi; } /* Generate Unique CPI numbers. * The result is returned as an SPI (4 bytes) in network order! * The real bits are in the nework-low-order 2 bytes. - * Modelled on get_ipsec_spi, but range is more limited: - * 256-61439. - * If we can't find one easily, return 0 (a bad SPI, - * no matter what order) indicating failure. */ ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel) { - static cpi_t first_busy_cpi = 0, latest_cpi; - char text_said[SATOT_BUF]; - rng_t *rng; + host_t *host_src, *host_dst; + u_int16_t cpi; - set_text_said(text_said, &sr->this.host_addr, 0, IPPROTO_COMP); + host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); + host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); - if (kernel_ops->get_spi) - { - return kernel_ops->get_spi(&sr->that.host_addr - , &sr->this.host_addr, IPPROTO_COMP, tunnel - , get_proto_reqid(sr->reqid, IPPROTO_COMP) - , IPCOMP_FIRST_NEGOTIATED, IPCOMP_LAST_NEGOTIATED - , text_said); - } + if (hydra->kernel_interface->get_cpi(hydra->kernel_interface, host_src, + host_dst, sr->reqid, &cpi) != SUCCESS) - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - while (!(IPCOMP_FIRST_NEGOTIATED <= first_busy_cpi && first_busy_cpi < IPCOMP_LAST_NEGOTIATED)) { - rng->get_bytes(rng, sizeof(first_busy_cpi), (u_char *)&first_busy_cpi); - latest_cpi = first_busy_cpi; + cpi = 0; } - rng->destroy(rng); - latest_cpi++; + host_src->destroy(host_src); + host_dst->destroy(host_dst); - if (latest_cpi == first_busy_cpi) - { - find_my_cpi_gap(&latest_cpi, &first_busy_cpi); - } - if (latest_cpi > IPCOMP_LAST_NEGOTIATED) - { - latest_cpi = IPCOMP_FIRST_NEGOTIATED; - } - return htonl((ipsec_spi_t)latest_cpi); + return htonl((u_int32_t)ntohs(cpi)); } /* Replace the shell metacharacters ', \, ", `, and $ in a character string @@ -420,7 +250,7 @@ static void escape_metachar(const char *src, char *dst, size_t dstlen) # define DEFAULT_UPDOWN "ipsec _updown" #endif -static bool do_command(connection_t *c, struct spd_route *sr, +static bool do_command(connection_t *c, struct spd_route *sr, struct state *st, const char *verb) { char cmd[1536]; /* arbitrary limit on shell command length */ @@ -464,6 +294,9 @@ static bool do_command(connection_t *c, struct spd_route *sr, peerclientnet_str[ADDRTOT_BUF], peerclientmask_str[ADDRTOT_BUF], peerca_str[BUF_LEN], + mark_in[BUF_LEN] = "", + mark_out[BUF_LEN] = "", + udp_encap[BUF_LEN] = "", xauth_id_str[BUF_LEN] = "", secure_myid_str[BUF_LEN] = "", secure_peerid_str[BUF_LEN] = "", @@ -491,11 +324,29 @@ static bool do_command(connection_t *c, struct spd_route *sr, strcpy(srcip_str, "PLUTO_MY_SOURCEIP='"); n = srcip_str + strlen(srcip_str); - snprintf(n, sizeof(srcip_str)-strlen(srcip_str), "%H", + snprintf(n, sizeof(srcip_str)-strlen(srcip_str), "%H", sr->this.host_srcip); strncat(srcip_str, "' ", sizeof(srcip_str)); } + if (sr->mark_in.value) + { + snprintf(mark_in, sizeof(mark_in), "PLUTO_MARK_IN='%u/0x%08x' ", + sr->mark_in.value, sr->mark_in.mask); + } + + if (sr->mark_out.value) + { + snprintf(mark_out, sizeof(mark_out), "PLUTO_MARK_OUT='%u/0x%08x' ", + sr->mark_out.value, sr->mark_out.mask); + } + + if (st && (st->nat_traversal & NAT_T_DETECTED)) + { + snprintf(udp_encap, sizeof(udp_encap), "PLUTO_UDP_ENC='%u' ", + sr->that.host_port); + } + addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); snprintf(myid_str, sizeof(myid_str), "%Y", sr->this.id); escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str)); @@ -536,7 +387,7 @@ static bool do_command(connection_t *c, struct spd_route *sr, { if (key->issuer) { - snprintf(peerca_str, BUF_LEN, "%Y", key->issuer); + snprintf(peerca_str, BUF_LEN, "%Y", key->issuer); escape_metachar(peerca_str, secure_peerca_str, BUF_LEN); } else @@ -573,13 +424,16 @@ static bool do_command(connection_t *c, struct spd_route *sr, "PLUTO_PEER_CA='%s' " "%s" /* optional PLUTO_MY_SRCIP */ "%s" /* optional PLUTO_XAUTH_ID */ + "%s" /* optional PLUTO_MARK_IN */ + "%s" /* optional PLUTO_MARK_OUT */ + "%s" /* optional PLUTO_UDP_ENC */ "%s" /* actual script */ , verb, verb_suffix , c->name , nexthop_str , c->interface->vname , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : "" - , sr->reqid + 1 /* ESP requid */ + , sr->reqid , me_str , secure_myid_str , myclient_str @@ -597,6 +451,9 @@ static bool do_command(connection_t *c, struct spd_route *sr, , secure_peerca_str , srcip_str , xauth_id_str + , mark_in + , mark_out + , udp_encap , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown)) { loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix); @@ -607,88 +464,83 @@ static bool do_command(connection_t *c, struct spd_route *sr, DBG(DBG_CONTROL, DBG_log("executing %s%s: %s" , verb, verb_suffix, cmd)); -#ifdef KLIPS - if (!no_klips) + /* invoke the script, catching stderr and stdout + * It may be of concern that some file descriptors will + * be inherited. For the ones under our control, we + * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. + * Any used by library routines (perhaps the resolver or syslog) + * will remain. + */ + FILE *f = popen(cmd, "r"); + + if (f == NULL) { - /* invoke the script, catching stderr and stdout - * It may be of concern that some file descriptors will - * be inherited. For the ones under our control, we - * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. - * Any used by library routines (perhaps the resolver or syslog) - * will remain. - */ - FILE *f = popen(cmd, "r"); + loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); + return FALSE; + } - if (f == NULL) - { - loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); - return FALSE; - } + /* log any output */ + for (;;) + { + /* if response doesn't fit in this buffer, it will be folded */ + char resp[256]; - /* log any output */ - for (;;) + if (fgets(resp, sizeof(resp), f) == NULL) { - /* if response doesn't fit in this buffer, it will be folded */ - char resp[256]; - - if (fgets(resp, sizeof(resp), f) == NULL) + if (ferror(f)) { - if (ferror(f)) - { - log_errno((e, "fgets failed on output of %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else - { - passert(feof(f)); - break; - } + log_errno((e, "fgets failed on output of %s%s command" + , verb, verb_suffix)); + return FALSE; } else { - char *e = resp + strlen(resp); - - if (e > resp && e[-1] == '\n') - e[-1] = '\0'; /* trim trailing '\n' */ - plog("%s%s output: %s", verb, verb_suffix, resp); + passert(feof(f)); + break; } } - - /* report on and react to return code */ + else { - int r = pclose(f); + char *e = resp + strlen(resp); - if (r == -1) - { - log_errno((e, "pclose failed for %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else if (WIFEXITED(r)) - { - if (WEXITSTATUS(r) != 0) - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d" - , verb, verb_suffix, WEXITSTATUS(r)); - return FALSE; - } - } - else if (WIFSIGNALED(r)) - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d" - , verb, verb_suffix, WTERMSIG(r)); - return FALSE; - } - else + if (e > resp && e[-1] == '\n') + e[-1] = '\0'; /* trim trailing '\n' */ + plog("%s%s output: %s", verb, verb_suffix, resp); + } + } + + /* report on and react to return code */ + { + int r = pclose(f); + + if (r == -1) + { + log_errno((e, "pclose failed for %s%s command" + , verb, verb_suffix)); + return FALSE; + } + else if (WIFEXITED(r)) + { + if (WEXITSTATUS(r) != 0) { - loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d" - , verb, verb_suffix, r); + loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d" + , verb, verb_suffix, WEXITSTATUS(r)); return FALSE; } } + else if (WIFSIGNALED(r)) + { + loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d" + , verb, verb_suffix, WTERMSIG(r)); + return FALSE; + } + else + { + loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d" + , verb, verb_suffix, r); + return FALSE; + } } -#endif /* KLIPS */ return TRUE; } @@ -731,10 +583,9 @@ static enum routability could_route(connection_t *c) } /* if routing would affect IKE messages, reject */ - if (!no_klips - && c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT - && c->spd.this.host_port != IKE_UDP_PORT - && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client)) + if (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT + && c->spd.this.host_port != IKE_UDP_PORT + && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client)) { loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client"); return route_impossible; @@ -754,7 +605,6 @@ static enum routability could_route(connection_t *c) using the eroute */ } -#ifdef KLIPS /* if there is an eroute for another connection, there is a problem */ if (ero != NULL && ero != c) { @@ -838,10 +688,9 @@ static enum routability could_route(connection_t *c) loglog(RC_LOG_SERIOUS , "cannot install eroute -- it is in use for \"%s\"%s #%lu" , ero->name, inst, esr->eroute_owner); - return FALSE; /* another connection already using the eroute */ + return route_impossible; } } -#endif /* KLIPS */ return route_easy; } @@ -886,9 +735,7 @@ void unroute_connection(connection_t *c) { /* cannot handle a live one */ passert(sr->routing != RT_ROUTED_TUNNEL); -#ifdef KLIPS shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete"); -#endif } sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */ @@ -896,14 +743,12 @@ void unroute_connection(connection_t *c) /* only unroute if no other connection shares it */ if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL) { - (void) do_command(c, sr, "unroute"); + (void) do_command(c, sr, NULL, "unroute"); } } } -#ifdef KLIPS - static void set_text_said(char *text_said, const ip_address *dst, ipsec_spi_t spi, int proto) { @@ -913,99 +758,36 @@ static void set_text_said(char *text_said, const ip_address *dst, satot(&said, 0, text_said, SATOT_BUF); } -/* find an entry in the bare_shunt table. - * Trick: return a pointer to the pointer to the entry; - * this allows the entry to be deleted. - */ -static struct bare_shunt** bare_shunt_ptr(const ip_subnet *ours, - const ip_subnet *his, - int transport_proto) -{ - struct bare_shunt *p, **pp; - for (pp = &bare_shunts; (p = *pp) != NULL; pp = &p->next) - { - if (samesubnet(ours, &p->ours) - && samesubnet(his, &p->his) - && transport_proto == p->transport_proto - && portof(&ours->addr) == portof(&p->ours.addr) - && portof(&his->addr) == portof(&p->his.addr)) - return pp; - } - return NULL; -} - -/* free a bare_shunt entry, given a pointer to the pointer */ -static void free_bare_shunt(struct bare_shunt **pp) -{ - if (pp == NULL) - { - DBG(DBG_CONTROL, - DBG_log("delete bare shunt: null pointer") - ) - } - else - { - struct bare_shunt *p = *pp; - - *pp = p->next; - DBG_bare_shunt("delete", p); - free(p->why); - free(p); - } -} - -void -show_shunt_status(void) -{ - struct bare_shunt *bs; - - for (bs = bare_shunts; bs != NULL; bs = bs->next) - { - /* Print interesting fields. Ignore count and last_active. */ - - int ourport = ntohs(portof(&bs->ours.addr)); - int hisport = ntohs(portof(&bs->his.addr)); - char ourst[SUBNETTOT_BUF]; - char hist[SUBNETTOT_BUF]; - char sat[SATOT_BUF]; - char prio[POLICY_PRIO_BUF]; - - subnettot(&(bs)->ours, 0, ourst, sizeof(ourst)); - subnettot(&(bs)->his, 0, hist, sizeof(hist)); - satot(&(bs)->said, 0, sat, sizeof(sat)); - fmt_policy_prio(bs->policy_prio, prio); - - whack_log(RC_COMMENT, "%s:%d -> %s:%d => %s:%d %s %s" - , ourst, ourport, hist, hisport, sat, bs->transport_proto - , prio, bs->why); - } - if (bare_shunts != NULL) - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ -} - -/* Setup an IPsec route entry. +/** + * Setup an IPsec route entry. * op is one of the ERO_* operators. */ - static bool raw_eroute(const ip_address *this_host, const ip_subnet *this_client, const ip_address *that_host, const ip_subnet *that_client, + mark_t mark, ipsec_spi_t spi, unsigned int proto, unsigned int satype, unsigned int transport_proto, - const struct pfkey_proto_info *proto_info, - time_t use_lifetime, + ipsec_sa_cfg_t *sa, unsigned int op, const char *opname USED_BY_DEBUG) { + traffic_selector_t *ts_src, *ts_dst; + host_t *host_src, *host_dst; + policy_type_t type = POLICY_IPSEC; + policy_dir_t dir = POLICY_OUT; char text_said[SATOT_BUF]; + bool ok = TRUE, routed = FALSE, + deleting = (op & ERO_MASK) == ERO_DELETE, + replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT); set_text_said(text_said, that_host, spi, proto); - DBG(DBG_CONTROL | DBG_KLIPS, + DBG(DBG_CONTROL | DBG_KERNEL, { int sport = ntohs(portof(&this_client->addr)); int dport = ntohs(portof(&that_client->addr)); @@ -1019,104 +801,86 @@ static bool raw_eroute(const ip_address *this_host, , text_said, transport_proto); }); - return kernel_ops->raw_eroute(this_host, this_client - , that_host, that_client, spi, satype, transport_proto, proto_info - , use_lifetime, op, text_said); -} - -/* test to see if %hold remains */ -bool has_bare_hold(const ip_address *src, const ip_address *dst, - int transport_proto) -{ - ip_subnet this_client, that_client; - struct bare_shunt **bspp; - - passert(addrtypeof(src) == addrtypeof(dst)); - happy(addrtosubnet(src, &this_client)); - happy(addrtosubnet(dst, &that_client)); - bspp = bare_shunt_ptr(&this_client, &that_client, transport_proto); - return bspp != NULL - && (*bspp)->said.proto == SA_INT && (*bspp)->said.spi == htonl(SPI_HOLD); -} + if (satype == SADB_X_SATYPE_INT) + { + switch (ntohl(spi)) + { + case SPI_PASS: + type = POLICY_PASS; + break; + case SPI_DROP: + case SPI_REJECT: + type = POLICY_DROP; + break; + case SPI_TRAP: + case SPI_TRAPSUBNET: + case SPI_HOLD: + if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) + { + return TRUE; + } + routed = TRUE; + break; + } + } + if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) + { + dir = POLICY_IN; + } -/* Replace (or delete) a shunt that is in the bare_shunts table. - * Issues the PF_KEY commands and updates the bare_shunts table. - */ -bool replace_bare_shunt(const ip_address *src, const ip_address *dst, - policy_prio_t policy_prio, ipsec_spi_t shunt_spi, - bool repl, unsigned int transport_proto, const char *why) -{ - ip_subnet this_client, that_client; - ip_subnet this_broad_client, that_broad_client; - const ip_address *null_host = aftoinfo(addrtypeof(src))->any; + host_src = host_create_from_sockaddr((sockaddr_t*)this_host); + host_dst = host_create_from_sockaddr((sockaddr_t*)that_host); + ts_src = traffic_selector_from_subnet(this_client, transport_proto); + ts_dst = traffic_selector_from_subnet(that_client, transport_proto); - passert(addrtypeof(src) == addrtypeof(dst)); - happy(addrtosubnet(src, &this_client)); - happy(addrtosubnet(dst, &that_client)); - this_broad_client = this_client; - that_broad_client = that_client; - setportof(0, &this_broad_client.addr); - setportof(0, &that_broad_client.addr); + if (deleting || replacing) + { + hydra->kernel_interface->del_policy(hydra->kernel_interface, + ts_src, ts_dst, dir, mark, routed); + } - if (repl) + if (!deleting) { - struct bare_shunt **bs_pp = bare_shunt_ptr(&this_broad_client - , &that_broad_client, 0); + ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, + host_src, host_dst, ts_src, ts_dst, dir, type, sa, + mark, routed) == SUCCESS; + } - /* is there already a broad host-to-host bare shunt? */ - if (bs_pp == NULL) + if (dir == POLICY_IN) + { /* handle forward policy */ + dir = POLICY_FWD; + if (deleting || replacing) { - if (raw_eroute(null_host, &this_broad_client, null_host, &that_broad_client - , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT - , 0, null_proto_info - , SHUNT_PATIENCE, ERO_ADD, why)) - { - struct bare_shunt *bs = malloc_thing(struct bare_shunt); - - bs->ours = this_broad_client; - bs->his = that_broad_client; - bs->transport_proto = 0; - bs->said.proto = SA_INT; - bs->why = clone_str(why); - bs->policy_prio = policy_prio; - bs->said.spi = htonl(shunt_spi); - bs->said.dst = *null_host; - bs->count = 0; - bs->last_activity = now(); - bs->next = bare_shunts; - bare_shunts = bs; - DBG_bare_shunt("add", bs); - } + hydra->kernel_interface->del_policy(hydra->kernel_interface, + ts_src, ts_dst, dir, mark, routed); + } + + if (!deleting && ok && + (sa->mode == MODE_TUNNEL || satype == SADB_X_SATYPE_INT)) + { + ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, + host_src, host_dst, ts_src, ts_dst, dir, type, sa, + mark, routed) == SUCCESS; } - shunt_spi = SPI_HOLD; } - if (raw_eroute(null_host, &this_client, null_host, &that_client - , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT - , transport_proto, null_proto_info - , SHUNT_PATIENCE, ERO_DELETE, why)) - { - struct bare_shunt **bs_pp = bare_shunt_ptr(&this_client, &that_client - , transport_proto); + host_src->destroy(host_src); + host_dst->destroy(host_dst); + ts_src->destroy(ts_src); + ts_dst->destroy(ts_dst); - /* delete bare eroute */ - free_bare_shunt(bs_pp); - return TRUE; - } - else - { - return FALSE; - } + return ok; } static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, unsigned int proto, unsigned int satype, - const struct pfkey_proto_info *proto_info, - unsigned int op, const char *opname) + ipsec_sa_cfg_t *sa, unsigned int op, + const char *opname) { const ip_address *peer = &sr->that.host_addr; char buf2[256]; + bool ok; snprintf(buf2, sizeof(buf2) , "eroute_connection %s", opname); @@ -1125,11 +889,13 @@ static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, { peer = aftoinfo(addrtypeof(peer))->any; } - return raw_eroute(&sr->this.host_addr, &sr->this.client - , peer - , &sr->that.client - , spi, proto, satype - , sr->this.protocol, proto_info, 0, op, buf2); + ok = raw_eroute(peer, &sr->that.client, + &sr->this.host_addr, &sr->this.client, sr->mark_in, + spi, proto, satype, sr->this.protocol, + sa, op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), buf2); + return raw_eroute(&sr->this.host_addr, &sr->this.client, peer, + &sr->that.client, sr->mark_out, spi, proto, satype, + sr->this.protocol, sa, op, buf2) && ok; } /* assign a bare hold to a connection */ @@ -1162,31 +928,24 @@ bool assign_hold(connection_t *c USED_BY_DEBUG, struct spd_route *sr, break; } - /* we need a broad %hold, not the narrow one. + /* We need a broad %hold * First we ensure that there is a broad %hold. * There may already be one (race condition): no need to create one. * There may already be a %trap: replace it. * There may not be any broad eroute: add %hold. - * Once the broad %hold is in place, delete the narrow one. */ if (rn != ro) { if (erouted(ro) - ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT - , null_proto_info - , ERO_REPLACE, "replace %trap with broad %hold") - : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT - , null_proto_info - , ERO_ADD, "add broad %hold")) + ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, + &null_ipsec_sa, ERO_REPLACE, + "replace %trap with broad %hold") + : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, + &null_ipsec_sa, ERO_ADD, "add broad %hold")) { return FALSE; } } - if (!replace_bare_shunt(src, dst, BOTTOM_PRIO, SPI_HOLD, FALSE - , transport_proto, "delete narrow %hold")) - { - return FALSE; - } sr->routing = rn; return TRUE; } @@ -1195,32 +954,21 @@ bool assign_hold(connection_t *c USED_BY_DEBUG, struct spd_route *sr, static bool sag_eroute(struct state *st, struct spd_route *sr, unsigned op, const char *opname) { - u_int inner_proto = 0; - u_int inner_satype = 0; + u_int inner_proto, inner_satype; ipsec_spi_t inner_spi = 0; - struct pfkey_proto_info proto_info[4]; - int i; - bool tunnel; - - /* figure out the SPI and protocol (in two forms) - * for the innermost transformation. - */ - - i = sizeof(proto_info) / sizeof(proto_info[0]) - 1; - proto_info[i].proto = 0; - tunnel = FALSE; + ipsec_sa_cfg_t sa = { + .mode = MODE_TRANSPORT, + }; + bool tunnel = FALSE; if (st->st_ah.present) { inner_spi = st->st_ah.attrs.spi; inner_proto = SA_AH; inner_satype = SADB_SATYPE_AH; - - i--; - proto_info[i].proto = IPPROTO_AH; - proto_info[i].encapsulation = st->st_ah.attrs.encapsulation; - tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - proto_info[i].reqid = sr->reqid; + sa.ah.use = TRUE; + sa.ah.spi = inner_spi; + tunnel |= st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; } if (st->st_esp.present) @@ -1228,12 +976,9 @@ static bool sag_eroute(struct state *st, struct spd_route *sr, inner_spi = st->st_esp.attrs.spi; inner_proto = SA_ESP; inner_satype = SADB_SATYPE_ESP; - - i--; - proto_info[i].proto = IPPROTO_ESP; - proto_info[i].encapsulation = st->st_esp.attrs.encapsulation; - tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - proto_info[i].reqid = sr->reqid + 1; + sa.esp.use = TRUE; + sa.esp.spi = inner_spi; + tunnel |= st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; } if (st->st_ipcomp.present) @@ -1241,37 +986,28 @@ static bool sag_eroute(struct state *st, struct spd_route *sr, inner_spi = st->st_ipcomp.attrs.spi; inner_proto = SA_COMP; inner_satype = SADB_X_SATYPE_COMP; - - i--; - proto_info[i].proto = IPPROTO_COMP; - proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation; - tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - proto_info[i].reqid = sr->reqid + 2; + sa.ipcomp.transform = st->st_ipcomp.attrs.transid; + sa.ipcomp.cpi = htons(ntohl(inner_spi)); + tunnel |= st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; } - if (i == sizeof(proto_info) / sizeof(proto_info[0]) - 1) + if (!sa.ah.use && !sa.esp.use && !sa.ipcomp.transform) { impossible(); /* no transform at all! */ } if (tunnel) { - int j; - inner_spi = st->st_tunnel_out_spi; inner_proto = SA_IPIP; inner_satype = SADB_X_SATYPE_IPIP; - - proto_info[i].encapsulation = ENCAPSULATION_MODE_TUNNEL; - for (j = i + 1; proto_info[j].proto; j++) - { - proto_info[j].encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } + sa.mode = MODE_TUNNEL; } - return eroute_connection(sr - , inner_spi, inner_proto, inner_satype, proto_info + i - , op, opname); + sa.reqid = sr->reqid; + + return eroute_connection(sr, inner_spi, inner_proto, inner_satype, + &sa, op, opname); } /* compute a (host-order!) SPI to implement the policy in connection c */ @@ -1318,7 +1054,6 @@ static bool shunt_eroute(connection_t *c, struct spd_route *sr, * The SPI signifies the kind of shunt. */ ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE); - bool ok; if (spi == 0) { @@ -1377,599 +1112,120 @@ static bool shunt_eroute(connection_t *c, struct spd_route *sr, } } - ok = TRUE; - if (kernel_ops->inbound_eroute) - { - ok = raw_eroute(&c->spd.that.host_addr, &c->spd.that.client - , &c->spd.this.host_addr, &c->spd.this.client - , htonl(spi), SA_INT, SADB_X_SATYPE_INT - , 0, null_proto_info, 0 - , op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), opname); - } - return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT - , null_proto_info, op, opname) && ok; -} - - -/* - * This is only called when s is a likely SAID with trailing protocol i.e. - * it has the form :- - * - * %<keyword>:p - * <ip-proto><spi>@a.b.c.d:p - * - * The task here is to remove the ":p" part so that the rest can be read - * by another routine. - */ -static const char *read_proto(const char * s, size_t * len, int * transport_proto) -{ - const char * p; - const char * ugh; - unsigned long proto; - size_t l; - - l = *len; - p = memchr(s, ':', l); - if (p == 0) - { - *transport_proto = 0; - return 0; - } - ugh = ttoul(p+1, l-((p-s)+1), 10, &proto); - if (ugh != 0) - { - return ugh; - } - if (proto > 65535) - { - return "protocol number is too large, legal range is 0-65535"; - } - *len = p-s; - *transport_proto = proto; - return 0; + return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT, + &null_ipsec_sa, op, opname); } - -/* scan /proc/net/ipsec_eroute every once in a while, looking for: - * - * - %hold shunts of which Pluto isn't aware. This situation could - * be caused by lost ACQUIRE messages. When found, they will - * added to orphan_holds. This in turn will lead to Opportunistic - * initiation. - * - * - other kinds of shunts that haven't been used recently. These will be - * deleted. They represent OE failures. - * - * - recording recent uses of tunnel eroutes so that rekeying decisions - * can be made for OE connections. - * - * Here are some sample lines: - * 10 10.3.2.1.0/24 -> 0.0.0.0/0 => %trap - * 259 10.3.2.1.115/32 -> 10.19.75.161/32 => tun0x1002@10.19.75.145 - * 71 10.44.73.97/32 -> 0.0.0.0/0 => %trap - * 4119 10.44.73.97/32 -> 10.114.121.41/32 => %pass - * Newer versions of KLIPS start each line with a 32-bit packet count. - * If available, the count is used to detect whether a %pass shunt is in use. - * - * NOTE: execution time is quadratic in the number of eroutes since the - * searching for each is sequential. If this becomes a problem, faster - * searches could be implemented (hash or radix tree, for example). - */ -void scan_proc_shunts(void) -{ - static const char procname[] = "/proc/net/ipsec_eroute"; - FILE *f; - time_t nw = now(); - int lino; - struct eroute_info *expired = NULL; - - event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL); - - DBG(DBG_CONTROL, - DBG_log("scanning for shunt eroutes") - ) - - /* free any leftover entries: they will be refreshed if still current */ - while (orphaned_holds != NULL) - { - struct eroute_info *p = orphaned_holds; - - orphaned_holds = p->next; - free(orphaned_holds); - } - - /* decode the /proc file. Don't do anything strenuous to it - * (certainly no PF_KEY stuff) to minimize the chance that it - * might change underfoot. - */ - - f = fopen(procname, "r"); - if (f == NULL) - { - return; - } - - /* for each line... */ - for (lino = 1; ; lino++) - { - unsigned char buf[1024]; /* should be big enough */ - chunk_t field[10]; /* 10 is loose upper bound */ - chunk_t *ff = NULL; /* fixed fields (excluding optional count) */ - int fi; - struct eroute_info eri; - char *cp; - err_t context = "" - , ugh = NULL; - - cp = fgets(buf, sizeof(buf), f); - if (cp == NULL) - { - break; - } - - /* break out each field - * Note: if there are too many fields, just stop; - * it will be diagnosed a little later. - */ - for (fi = 0; fi < (int)countof(field); fi++) - { - static const char sep[] = " \t\n"; /* field-separating whitespace */ - size_t w; - - cp += strspn(cp, sep); /* find start of field */ - w = strcspn(cp, sep); /* find width of field */ - field[fi] = chunk_create(cp, w); - cp += w; - if (w == 0) - { - break; - } - } - - /* This odd do-hickey is to share error reporting code. - * A break will get to that common code. The setting - * of "ugh" and "context" parameterize it. - */ - do { - /* Old entries have no packet count; new ones do. - * check if things are as they should be. - */ - if (fi == 5) - { - ff = &field[0]; /* old form, with no count */ - } - else if (fi == 6) - { - ff = &field[1]; /* new form, with count */ - } - else - { - ugh = "has wrong number of fields"; - break; - } - - if (ff[1].len != 2 - || strncmp(ff[1].ptr, "->", 2) != 0 - || ff[3].len != 2 - || strncmp(ff[3].ptr, "=>", 2) != 0) - { - ugh = "is missing -> or =>"; - break; - } - - /* actually digest fields of interest */ - - /* packet count */ - - eri.count = 0; - if (ff != field) - { - context = "count field is malformed: "; - ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count); - if (ugh != NULL) - { - break; - } - } - - /* our client */ - - context = "source subnet field malformed: "; - ugh = ttosubnet(ff[0].ptr, ff[0].len, AF_INET, &eri.ours); - if (ugh != NULL) - { - break; - } - - /* his client */ - - context = "destination subnet field malformed: "; - ugh = ttosubnet(ff[2].ptr, ff[2].len, AF_INET, &eri.his); - if (ugh != NULL) - { - break; - } - - /* SAID */ - - context = "SA ID field malformed: "; - ugh = read_proto(ff[4].ptr, &ff[4].len, &eri.transport_proto); - if (ugh != NULL) - { - break; - } - ugh = ttosa(ff[4].ptr, ff[4].len, &eri.said); - } while (FALSE); - - if (ugh != NULL) - { - plog("INTERNAL ERROR: %s line %d %s%s" - , procname, lino, context, ugh); - continue; /* ignore rest of line */ - } - - /* Now we have decoded eroute, let's consider it. - * For shunt eroutes: - * - * %hold: if not known, add to orphaned_holds list for initiation - * because ACQUIRE might have been lost. - * - * %pass, %drop, %reject: determine if idle; if so, blast it away. - * Can occur bare (if DNS provided insufficient information) - * or with a connection (failure context). - * Could even be installed by ipsec manual. - * - * %trap: always welcome. - * - * For other eroutes: find state and record count change - */ - if (eri.said.proto == SA_INT) - { - /* shunt eroute */ - switch (ntohl(eri.said.spi)) - { - case SPI_HOLD: - if (bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto) == NULL - && shunt_owner(&eri.ours, &eri.his) == NULL) - { - int ourport = ntohs(portof(&eri.ours.addr)); - int hisport = ntohs(portof(&eri.his.addr)); - char ourst[SUBNETTOT_BUF]; - char hist[SUBNETTOT_BUF]; - char sat[SATOT_BUF]; - - subnettot(&eri.ours, 0, ourst, sizeof(ourst)); - subnettot(&eri.his, 0, hist, sizeof(hist)); - satot(&eri.said, 0, sat, sizeof(sat)); - - DBG(DBG_CONTROL, - DBG_log("add orphaned shunt %s:%d -> %s:%d => %s:%d" - , ourst, ourport, hist, hisport, sat, eri.transport_proto) - ) - eri.next = orphaned_holds; - orphaned_holds = clone_thing(eri); - } - break; - - case SPI_PASS: - case SPI_DROP: - case SPI_REJECT: - /* nothing sensible to do if we don't have counts */ - if (ff != field) - { - struct bare_shunt **bs_pp - = bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto); - - if (bs_pp != NULL) - { - struct bare_shunt *bs = *bs_pp; - - if (eri.count != bs->count) - { - bs->count = eri.count; - bs->last_activity = nw; - } - else if (nw - bs->last_activity > SHUNT_PATIENCE) - { - eri.next = expired; - expired = clone_thing(eri); - } - } - } - break; - - case SPI_TRAP: - break; - - default: - bad_case(ntohl(eri.said.spi)); - } - } - else - { - /* regular (non-shunt) eroute */ - state_eroute_usage(&eri.ours, &eri.his, eri.count, nw); - } - } /* for each line */ - fclose(f); - - /* Now that we've finished processing the /proc file, - * it is safe to delete the expired %pass shunts. - */ - while (expired != NULL) - { - struct eroute_info *p = expired; - ip_address src, dst; - - networkof(&p->ours, &src); - networkof(&p->his, &dst); - (void) replace_bare_shunt(&src, &dst - , BOTTOM_PRIO /* not used because we are deleting. This value is a filler */ - , SPI_PASS /* not used because we are deleting. This value is a filler */ - , FALSE, p->transport_proto, "delete expired bare shunts"); - expired = p->next; - free(p); - } -} - -static bool del_spi(ipsec_spi_t spi, int proto, - const ip_address *src, const ip_address *dest) -{ - char text_said[SATOT_BUF]; - struct kernel_sa sa; - - set_text_said(text_said, dest, spi, proto); - - DBG(DBG_KLIPS, DBG_log("delete %s", text_said)); - - memset(&sa, 0, sizeof(sa)); - sa.spi = spi; - sa.proto = proto; - sa.src = src; - sa.dst = dest; - sa.text_said = text_said; - - return kernel_ops->del_sa(&sa); -} - -/* Setup a pair of SAs. Code taken from setsa.c and spigrp.c, in - * ipsec-0.5. - */ - static bool setup_half_ipsec_sa(struct state *st, bool inbound) { - /* Build an inbound or outbound SA */ - + host_t *host_src, *host_dst; connection_t *c = st->st_connection; - ip_subnet src, dst; - ip_subnet src_client, dst_client; - ipsec_spi_t inner_spi = 0; - u_int proto = 0; - u_int satype = SADB_SATYPE_UNSPEC; - bool replace; - - /* SPIs, saved for spigrouping or undoing, if necessary */ - struct kernel_sa - said[EM_MAXRELSPIS], - *said_next = said; - - char text_said[SATOT_BUF]; - int encapsulation; - - replace = inbound && (kernel_ops->get_spi != NULL); - - src.maskbits = 0; - dst.maskbits = 0; - + struct end *src, *dst; + ipsec_mode_t mode = MODE_TRANSPORT; + ipsec_sa_cfg_t sa = { .mode = 0 }; + lifetime_cfg_t lt_none = { .time = { .rekey = 0 } }; + mark_t mark; + bool ok = TRUE; + /* SPIs, saved for undoing, if necessary */ + struct kernel_sa said[EM_MAXRELSPIS], *said_next = said; if (inbound) { - src.addr = c->spd.that.host_addr; - dst.addr = c->spd.this.host_addr; - src_client = c->spd.that.client; - dst_client = c->spd.this.client; + src = &c->spd.that; + dst = &c->spd.this; + mark = c->spd.mark_in; } else { - src.addr = c->spd.this.host_addr, - dst.addr = c->spd.that.host_addr; - src_client = c->spd.this.client; - dst_client = c->spd.that.client; + src = &c->spd.this; + dst = &c->spd.that; + mark = c->spd.mark_out; } - encapsulation = ENCAPSULATION_MODE_TRANSPORT; + host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); + host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); + if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) { - encapsulation = ENCAPSULATION_MODE_TUNNEL; + mode = MODE_TUNNEL; } - memset(said, 0, sizeof(said)); - - /* If we are tunnelling, set up IP in IP pseudo SA */ - - if (kernel_ops->inbound_eroute) - { - inner_spi = 256; - proto = SA_IPIP; - satype = SADB_SATYPE_UNSPEC; - } - else if (encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - /* XXX hack alert -- we SHOULD NOT HAVE TO HAVE A DIFFERENT SPI - * XXX FOR IP-in-IP ENCAPSULATION! - */ - - ipsec_spi_t ipip_spi; - - /* Allocate an SPI for the tunnel. - * Since our peer will never see this, - * and it comes from its own number space, - * it is purely a local implementation wart. - */ - { - static ipsec_spi_t last_tunnel_spi = IPSEC_DOI_SPI_OUR_MIN; - - ipip_spi = htonl(++last_tunnel_spi); - if (inbound) - { - st->st_tunnel_in_spi = ipip_spi; - } - else - { - st->st_tunnel_out_spi = ipip_spi; - } - } - - set_text_said(text_said - , &c->spd.that.host_addr, ipip_spi, SA_IPIP); - - said_next->src = &src.addr; - said_next->dst = &dst.addr; - said_next->src_client = &src_client; - said_next->dst_client = &dst_client; - said_next->spi = ipip_spi; - said_next->satype = SADB_X_SATYPE_IPIP; - said_next->text_said = text_said; - - if (!kernel_ops->add_sa(said_next, replace)) - goto fail; - - said_next++; + sa.mode = mode; + sa.reqid = c->spd.reqid; - inner_spi = ipip_spi; - proto = SA_IPIP; - satype = SADB_X_SATYPE_IPIP; - } + memset(said, 0, sizeof(said)); /* set up IPCOMP SA, if any */ if (st->st_ipcomp.present) { - ipsec_spi_t ipcomp_spi = inbound? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; - unsigned compalg; + ipsec_spi_t ipcomp_spi = inbound ? st->st_ipcomp.our_spi + : st->st_ipcomp.attrs.spi; switch (st->st_ipcomp.attrs.transid) { case IPCOMP_DEFLATE: - compalg = SADB_X_CALG_DEFLATE; break; default: - loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented" - , enum_name(&ipcomp_transformid_names, st->st_ipcomp.attrs.transid)); + loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented", + enum_name(&ipcomp_transformid_names, + st->st_ipcomp.attrs.transid)); goto fail; } - set_text_said(text_said, &dst.addr, ipcomp_spi, SA_COMP); + sa.ipcomp.cpi = htons(ntohl(ipcomp_spi)); + sa.ipcomp.transform = st->st_ipcomp.attrs.transid; - said_next->src = &src.addr; - said_next->dst = &dst.addr; - said_next->src_client = &src_client; - said_next->dst_client = &dst_client; said_next->spi = ipcomp_spi; - said_next->satype = SADB_X_SATYPE_COMP; - said_next->compalg = compalg; - said_next->encapsulation = encapsulation; - said_next->reqid = c->spd.reqid + 2; - said_next->text_said = text_said; + said_next->proto = IPPROTO_COMP; - if (!kernel_ops->add_sa(said_next, replace)) + if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, + host_dst, ipcomp_spi, said_next->proto, c->spd.reqid, + mark, <_none, ENCR_UNDEFINED, chunk_empty, + AUTH_UNDEFINED, chunk_empty, mode, + st->st_ipcomp.attrs.transid, 0 /* cpi */, FALSE, + inbound, NULL, NULL) != SUCCESS) { goto fail; } said_next++; - encapsulation = ENCAPSULATION_MODE_TRANSPORT; + mode = MODE_TRANSPORT; } /* set up ESP SA, if any */ if (st->st_esp.present) { - ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi; - u_char *esp_dst_keymat = inbound? st->st_esp.our_keymat : st->st_esp.peer_keymat; + ipsec_spi_t esp_spi = inbound ? st->st_esp.our_spi + : st->st_esp.attrs.spi; + u_char *esp_dst_keymat = inbound ? st->st_esp.our_keymat + : st->st_esp.peer_keymat; + bool encap = st->nat_traversal & NAT_T_DETECTED; + encryption_algorithm_t enc_alg; + integrity_algorithm_t auth_alg; const struct esp_info *ei; + chunk_t enc_key, auth_key; u_int16_t key_len; - static const struct esp_info esp_info[] = { - { ESP_NULL, AUTH_ALGORITHM_HMAC_MD5, - 0, HMAC_MD5_KEY_LEN, - SADB_EALG_NULL, SADB_AALG_MD5HMAC }, - { ESP_NULL, AUTH_ALGORITHM_HMAC_SHA1, - 0, HMAC_SHA1_KEY_LEN, - SADB_EALG_NULL, SADB_AALG_SHA1HMAC }, - - { ESP_DES, AUTH_ALGORITHM_NONE, - DES_CBC_BLOCK_SIZE, 0, - SADB_EALG_DESCBC, SADB_AALG_NONE }, - { ESP_DES, AUTH_ALGORITHM_HMAC_MD5, - DES_CBC_BLOCK_SIZE, HMAC_MD5_KEY_LEN, - SADB_EALG_DESCBC, SADB_AALG_MD5HMAC }, - { ESP_DES, AUTH_ALGORITHM_HMAC_SHA1, - DES_CBC_BLOCK_SIZE, - HMAC_SHA1_KEY_LEN, SADB_EALG_DESCBC, SADB_AALG_SHA1HMAC }, - - { ESP_3DES, AUTH_ALGORITHM_NONE, - DES_CBC_BLOCK_SIZE * 3, 0, - SADB_EALG_3DESCBC, SADB_AALG_NONE }, - { ESP_3DES, AUTH_ALGORITHM_HMAC_MD5, - DES_CBC_BLOCK_SIZE * 3, HMAC_MD5_KEY_LEN, - SADB_EALG_3DESCBC, SADB_AALG_MD5HMAC }, - { ESP_3DES, AUTH_ALGORITHM_HMAC_SHA1, - DES_CBC_BLOCK_SIZE * 3, HMAC_SHA1_KEY_LEN, - SADB_EALG_3DESCBC, SADB_AALG_SHA1HMAC }, - }; - - u_int8_t natt_type = 0; - u_int16_t natt_sport = 0; - u_int16_t natt_dport = 0; - ip_address natt_oa; - - if (st->nat_traversal & NAT_T_DETECTED) - { - natt_type = (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) ? - ESPINUDP_WITH_NON_ESP : ESPINUDP_WITH_NON_IKE; - natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port; - natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port; - natt_oa = st->nat_oa; - } - - for (ei = esp_info; ; ei++) + if ((ei = kernel_alg_esp_info(st->st_esp.attrs.transid, + st->st_esp.attrs.auth)) == NULL) { - if (ei == &esp_info[countof(esp_info)]) - { - /* Check for additional kernel alg */ - if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid, - st->st_esp.attrs.auth))!=NULL) - { - break; - } - - /* note: enum_show may use a static buffer, so two - * calls in one printf would be a mistake. - * enum_name does the same job, without a static buffer, - * assuming the name will be found. - */ - loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s not implemented yet" - , enum_name(&esp_transform_names, st->st_esp.attrs.transid) - , enum_name(&auth_alg_names, st->st_esp.attrs.auth)); - goto fail; - } - - if (st->st_esp.attrs.transid == ei->transid && - st->st_esp.attrs.auth == ei->auth) - { - break; - } + loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s" + " not implemented yet", + enum_name(&esp_transform_names, st->st_esp.attrs.transid), + enum_name(&auth_alg_names, st->st_esp.attrs.auth)); + goto fail; } - key_len = st->st_esp.attrs.key_len/8; + key_len = st->st_esp.attrs.key_len / 8; if (key_len) { /* XXX: must change to check valid _range_ key_len */ if (key_len > ei->enckeylen) { - loglog(RC_LOG_SERIOUS, "ESP transform %s passed key_len=%d > %d", + loglog(RC_LOG_SERIOUS, "ESP transform %s: key_len=%d > %d", enum_name(&esp_transform_names, st->st_esp.attrs.transid), (int)key_len, (int)ei->enckeylen); goto fail; @@ -2012,290 +1268,144 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) break; } - /* divide up keying material */ - set_text_said(text_said, &dst.addr, esp_spi, SA_ESP); - said_next->src = &src.addr; - said_next->dst = &dst.addr; - said_next->src_client = &src_client; - said_next->dst_client = &dst_client; - said_next->spi = esp_spi; - said_next->satype = SADB_SATYPE_ESP; - said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? - REPLAY_WINDOW : REPLAY_WINDOW_XFRM; - said_next->authalg = ei->authalg; - said_next->authkeylen = ei->authkeylen; - said_next->authkey = esp_dst_keymat + key_len; - said_next->encalg = ei->encryptalg; - said_next->enckeylen = key_len; - said_next->enckey = esp_dst_keymat; - said_next->encapsulation = encapsulation; - said_next->reqid = c->spd.reqid + 1; - said_next->natt_sport = natt_sport; - said_next->natt_dport = natt_dport; - said_next->transid = st->st_esp.attrs.transid; - said_next->natt_type = natt_type; - said_next->natt_oa = &natt_oa; - said_next->text_said = text_said; - - if (!kernel_ops->add_sa(said_next, replace)) + if (encap) { - goto fail; + host_src->set_port(host_src, src->host_port); + host_dst->set_port(host_dst, dst->host_port); + // st->nat_oa is currently unused } - said_next++; - encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } - - /* set up AH SA, if any */ - if (st->st_ah.present) - { - ipsec_spi_t ah_spi = inbound? st->st_ah.our_spi : st->st_ah.attrs.spi; - u_char *ah_dst_keymat = inbound? st->st_ah.our_keymat : st->st_ah.peer_keymat; + /* divide up keying material */ + enc_alg = encryption_algorithm_from_esp(st->st_esp.attrs.transid); + enc_key.ptr = esp_dst_keymat; + enc_key.len = key_len; + auth_alg = integrity_algorithm_from_esp(st->st_esp.attrs.auth); + auth_alg = auth_alg ? : AUTH_UNDEFINED; + auth_key.ptr = esp_dst_keymat + key_len; + auth_key.len = ei->authkeylen; - unsigned char authalg; + sa.esp.use = TRUE; + sa.esp.spi = esp_spi; - switch (st->st_ah.attrs.auth) - { - case AUTH_ALGORITHM_HMAC_MD5: - authalg = SADB_AALG_MD5HMAC; - break; - case AUTH_ALGORITHM_HMAC_SHA1: - authalg = SADB_AALG_SHA1HMAC; - break; - default: - loglog(RC_LOG_SERIOUS, "%s not implemented yet", - enum_show(&auth_alg_names, st->st_ah.attrs.auth)); - goto fail; - } + said_next->spi = esp_spi; + said_next->proto = IPPROTO_ESP; - set_text_said(text_said, &dst.addr, ah_spi, SA_AH); - said_next->src = &src.addr; - said_next->dst = &dst.addr; - said_next->src_client = &src_client; - said_next->dst_client = &dst_client; - said_next->spi = ah_spi; - said_next->satype = SADB_SATYPE_AH; - said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? - REPLAY_WINDOW : REPLAY_WINDOW_XFRM; - said_next->authalg = authalg; - said_next->authkeylen = st->st_ah.keymat_len; - said_next->authkey = ah_dst_keymat; - said_next->encapsulation = encapsulation; - said_next->reqid = c->spd.reqid; - said_next->text_said = text_said; - - if (!kernel_ops->add_sa(said_next, replace)) + if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, + host_dst, esp_spi, said_next->proto, c->spd.reqid, + mark, <_none, enc_alg, enc_key, + auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, + encap, inbound, NULL, NULL) != SUCCESS) { goto fail; } said_next++; - encapsulation = ENCAPSULATION_MODE_TRANSPORT; + mode = MODE_TRANSPORT; } - if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - encapsulation = ENCAPSULATION_MODE_TUNNEL; - } + /* set up AH SA, if any */ - if (kernel_ops->inbound_eroute ? c->spd.eroute_owner == SOS_NOBODY - : encapsulation == ENCAPSULATION_MODE_TUNNEL) + if (st->st_ah.present) { - /* If inbound, and policy does not specifie DISABLEARRIVALCHECK, - * tell KLIPS to enforce the IP addresses appropriate for this tunnel. - * Note reversed ends. - * Not much to be done on failure. - */ - if (inbound && (c->policy & POLICY_DISABLEARRIVALCHECK) == 0) - { - struct pfkey_proto_info proto_info[4]; - int i = 0; - - if (st->st_ipcomp.present) - { - proto_info[i].proto = IPPROTO_COMP; - proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation; - proto_info[i].reqid = c->spd.reqid + 2; - i++; - } - - if (st->st_esp.present) - { - proto_info[i].proto = IPPROTO_ESP; - proto_info[i].encapsulation = st->st_esp.attrs.encapsulation; - proto_info[i].reqid = c->spd.reqid + 1; - i++; - } - - if (st->st_ah.present) - { - proto_info[i].proto = IPPROTO_AH; - proto_info[i].encapsulation = st->st_ah.attrs.encapsulation; - proto_info[i].reqid = c->spd.reqid; - i++; - } - - proto_info[i].proto = 0; - - if (kernel_ops->inbound_eroute - && encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - proto_info[0].encapsulation = ENCAPSULATION_MODE_TUNNEL; - for (i = 1; proto_info[i].proto; i++) - { - proto_info[i].encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } - } + ipsec_spi_t ah_spi = inbound ? st->st_ah.our_spi + : st->st_ah.attrs.spi; + u_char *ah_dst_keymat = inbound ? st->st_ah.our_keymat + : st->st_ah.peer_keymat; + integrity_algorithm_t auth_alg; + chunk_t auth_key; - /* MCR - should be passed a spd_eroute structure here */ - (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client - , &c->spd.this.host_addr, &c->spd.this.client - , inner_spi, proto, satype, c->spd.this.protocol - , proto_info, 0 - , ERO_ADD_INBOUND, "add inbound"); - } - } + auth_alg = integrity_algorithm_from_esp(st->st_ah.attrs.auth); + auth_key.ptr = ah_dst_keymat; + auth_key.len = st->st_ah.keymat_len; - /* If there are multiple SPIs, group them. */ + sa.ah.use = TRUE; + sa.ah.spi = ah_spi; - if (kernel_ops->grp_sa && said_next > &said[1]) - { - struct kernel_sa *s; + said_next->spi = ah_spi; + said_next->proto = IPPROTO_AH; - /* group SAs, two at a time, inner to outer (backwards in said[]) - * The grouping is by pairs. So if said[] contains ah esp ipip, - * the grouping would be ipip:esp, esp:ah. - */ - for (s = said; s < said_next-1; s++) + if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, + host_dst, ah_spi, said_next->proto, c->spd.reqid, + mark, <_none, ENCR_UNDEFINED, chunk_empty, + auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, + FALSE, inbound, NULL, NULL) != SUCCESS) { - char - text_said0[SATOT_BUF], - text_said1[SATOT_BUF]; - - /* group s[1] and s[0], in that order */ - - set_text_said(text_said0, s[0].dst, s[0].spi, s[0].proto); - set_text_said(text_said1, s[1].dst, s[1].spi, s[1].proto); - - DBG(DBG_KLIPS, DBG_log("grouping %s and %s", text_said1, text_said0)); - - s[0].text_said = text_said0; - s[1].text_said = text_said1; - - if (!kernel_ops->grp_sa(s + 1, s)) - { - goto fail; - } + goto fail; } - /* could update said, but it will not be used */ + said_next++; + mode = MODE_TRANSPORT; } - return TRUE; + goto cleanup; fail: + /* undo the done SPIs */ + while (said_next-- != said) { - /* undo the done SPIs */ - while (said_next-- != said) - { - (void) del_spi(said_next->spi, said_next->proto, &src.addr, - said_next->dst); - } - return FALSE; + hydra->kernel_interface->del_sa(hydra->kernel_interface, host_src, + host_dst, said_next->spi, + said_next->proto, 0 /* cpi */, + mark); } -} + ok = FALSE; -/* teardown_ipsec_sa is a canibalized version of setup_ipsec_sa */ +cleanup: + host_src->destroy(host_src); + host_dst->destroy(host_dst); + return ok; +} static bool teardown_half_ipsec_sa(struct state *st, bool inbound) { - /* We need to delete AH, ESP, and IP in IP SPIs. - * But if there is more than one, they have been grouped - * so deleting any one will do. So we just delete the - * first one found. It may or may not be the only one. - */ connection_t *c = st->st_connection; - struct { - unsigned proto; - struct ipsec_proto_info *info; - } protos[4]; - int i; - bool result; + const struct end *src, *dst; + host_t *host_src, *host_dst; + ipsec_spi_t spi; + mark_t mark; + bool result = TRUE; - i = 0; - if (kernel_ops->inbound_eroute && inbound - && c->spd.eroute_owner == SOS_NOBODY) + if (inbound) { - (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client - , &c->spd.this.host_addr, &c->spd.this.client - , 256, IPSEC_PROTO_ANY, SADB_SATYPE_UNSPEC, c->spd.this.protocol - , null_proto_info, 0 - , ERO_DEL_INBOUND, "delete inbound"); + src = &c->spd.that; + dst = &c->spd.this; + mark = c->spd.mark_in; } - - if (!kernel_ops->grp_sa) + else { - if (st->st_ah.present) - { - protos[i].info = &st->st_ah; - protos[i].proto = SA_AH; - i++; - } + src = &c->spd.this; + dst = &c->spd.that; + mark = c->spd.mark_out; + } - if (st->st_esp.present) - { - protos[i].info = &st->st_esp; - protos[i].proto = SA_ESP; - i++; - } + host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); + host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - if (st->st_ipcomp.present) - { - protos[i].info = &st->st_ipcomp; - protos[i].proto = SA_COMP; - i++; - } - } - else if (st->st_ah.present) - { - protos[i].info = &st->st_ah; - protos[i].proto = SA_AH; - i++; - } - else if (st->st_esp.present) + if (st->st_ah.present) { - protos[i].info = &st->st_esp; - protos[i].proto = SA_ESP; - i++; + spi = inbound ? st->st_ah.our_spi : st->st_ah.attrs.spi; + result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, + host_src, host_dst, spi, IPPROTO_AH, + 0 /* cpi */, mark) == SUCCESS; } - else + + if (st->st_esp.present) { - impossible(); /* neither AH nor ESP in outbound SA bundle! */ + spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; + result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, + host_src, host_dst, spi, IPPROTO_ESP, + 0 /* cpi */, mark) == SUCCESS; } - protos[i].proto = 0; - result = TRUE; - for (i = 0; protos[i].proto; i++) + if (st->st_ipcomp.present) { - unsigned proto = protos[i].proto; - ipsec_spi_t spi; - const ip_address *src, *dst; + spi = inbound ? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; + result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, + host_src, host_dst, spi, IPPROTO_COMP, + 0 /* cpi */, mark) == SUCCESS; + } - if (inbound) - { - spi = protos[i].info->our_spi; - src = &c->spd.that.host_addr; - dst = &c->spd.this.host_addr; - } - else - { - spi = protos[i].info->attrs.spi; - src = &c->spd.this.host_addr; - dst = &c->spd.that.host_addr; - } + host_src->destroy(host_src); + host_dst->destroy(host_dst); - result &= del_spi(spi, proto, src, dst); - } return result; } @@ -2304,126 +1414,198 @@ static bool teardown_half_ipsec_sa(struct state *st, bool inbound) */ bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time) { - char text_said[SATOT_BUF]; - struct kernel_sa sa; connection_t *c = st->st_connection; + traffic_selector_t *ts_src = NULL, *ts_dst = NULL; + host_t *host_src = NULL, *host_dst = NULL; + const struct end *src, *dst; + ipsec_spi_t spi; + mark_t mark; + u_int64_t bytes_kernel = 0; + bool result = FALSE; *use_time = UNDEFINED_TIME; - if (kernel_ops->get_sa == NULL || !st->st_esp.present) + if (!st->st_esp.present) { - return FALSE; + goto failed; } - memset(&sa, 0, sizeof(sa)); - sa.proto = SA_ESP; if (inbound) { - sa.src = &c->spd.that.host_addr; - sa.dst = &c->spd.this.host_addr; - sa.spi = st->st_esp.our_spi; + src = &c->spd.that; + dst = &c->spd.this; + mark = c->spd.mark_in; + spi = st->st_esp.our_spi; } else { - sa.src = &c->spd.this.host_addr; - sa.dst = &c->spd.that.host_addr; - sa.spi = st->st_esp.attrs.spi; + src = &c->spd.this; + dst = &c->spd.that; + mark = c->spd.mark_out; + spi = st->st_esp.attrs.spi; } - set_text_said(text_said, sa.dst, sa.spi, sa.proto); - sa.text_said = text_said; + host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); + host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - DBG(DBG_KLIPS, - DBG_log("get %s", text_said) - ) - if (!kernel_ops->get_sa(&sa, bytes)) + switch(hydra->kernel_interface->query_sa(hydra->kernel_interface, host_src, + host_dst, spi, IPPROTO_ESP, + mark, &bytes_kernel)) { - return FALSE; + case FAILED: + goto failed; + case SUCCESS: + *bytes = bytes_kernel; + break; + case NOT_SUPPORTED: + default: + break; } - DBG(DBG_KLIPS, - DBG_log(" current: %d bytes", *bytes) - ) if (st->st_serialno == c->spd.eroute_owner) { - DBG(DBG_KLIPS, - DBG_log("get %sbound policy with reqid %u" - , inbound? "in":"out", (u_int)c->spd.reqid + 1) - ) - sa.transport_proto = c->spd.this.protocol; - sa.encapsulation = st->st_esp.attrs.encapsulation; + u_int32_t time_kernel; - if (inbound) - { - sa.src_client = &c->spd.that.client; - sa.dst_client = &c->spd.this.client; - } - else + ts_src = traffic_selector_from_subnet(&src->client, src->protocol); + ts_dst = traffic_selector_from_subnet(&dst->client, dst->protocol); + + if (hydra->kernel_interface->query_policy(hydra->kernel_interface, + ts_src, ts_dst, inbound ? POLICY_IN : POLICY_OUT, + mark, &time_kernel) != SUCCESS) { - sa.src_client = &c->spd.this.client; - sa.dst_client = &c->spd.that.client; + goto failed; } - if (!kernel_ops->get_policy(&sa, inbound, use_time)) + *use_time = time_kernel; + + if (inbound && + st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) { - return FALSE; + if (hydra->kernel_interface->query_policy(hydra->kernel_interface, + ts_src, ts_dst, POLICY_FWD, mark, + &time_kernel) != SUCCESS) + { + goto failed; + } + *use_time = max(*use_time, time_kernel); } - DBG(DBG_KLIPS, - DBG_log(" use_time: %T", use_time, FALSE) - ) } - return TRUE; + + result = TRUE; + +failed: + DESTROY_IF(host_src); + DESTROY_IF(host_dst); + DESTROY_IF(ts_src); + DESTROY_IF(ts_dst); + return result; } -const struct kernel_ops *kernel_ops; +/** + * Handler for kernel events (called by thread-pool thread) + */ +kernel_listener_t *kernel_handler; -#endif /* KLIPS */ +/** + * Data for acquire events + */ +typedef struct { + /** Subnets */ + ip_subnet src, dst; + /** Transport protocol */ + int proto; +} acquire_data_t; -void init_kernel(void) +/** + * Callback for acquire events (called by main thread) + */ +void handle_acquire(acquire_data_t *this) { -#ifdef KLIPS + record_and_initiate_opportunistic(&this->src, &this->dst, this->proto, + "%acquire"); +} - if (no_klips) +METHOD(kernel_listener_t, acquire, bool, + kernel_listener_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts) +{ + if (src_ts && dst_ts) { - kernel_ops = &noklips_kernel_ops; - return; + acquire_data_t *data; + DBG(DBG_CONTROL, + DBG_log("creating acquire event for policy %R === %R " + "with reqid {%u}", src_ts, dst_ts, reqid)); + INIT(data, + .src = subnet_from_traffic_selector(src_ts), + .dst = subnet_from_traffic_selector(dst_ts), + .proto = src_ts->get_protocol(src_ts), + ); + pluto->events->queue(pluto->events, (void*)handle_acquire, data, free); } + else + { + DBG(DBG_CONTROL, + DBG_log("ignoring acquire without traffic selectors for policy " + "with reqid {%u}", reqid)); + } + DESTROY_IF(src_ts); + DESTROY_IF(dst_ts); + return TRUE; +} - init_pfkey(); - - kernel_ops = &klips_kernel_ops; +/** + * Data for mapping events + */ +typedef struct { + /** reqid, spi of affected SA */ + u_int32_t reqid, spi; + /** new endpont */ + ip_address new_end; +} mapping_data_t; -#if defined(linux) && defined(KERNEL26_SUPPORT) - { - bool linux_ipsec = 0; - struct stat buf; +/** + * Callback for mapping events (called by main thread) + */ +void handle_mapping(mapping_data_t *this) +{ + process_nat_t_new_mapping(this->reqid, this->spi, &this->new_end); +} - linux_ipsec = (stat("/proc/net/pfkey", &buf) == 0); - if (linux_ipsec) - { - plog("Using Linux 2.6 IPsec interface code"); - kernel_ops = &linux_kernel_ops; - } - else - { - plog("Using KLIPS IPsec interface code"); - } - } -#endif - if (kernel_ops->init) - { - kernel_ops->init(); - } +METHOD(kernel_listener_t, mapping, bool, + kernel_listener_t *this, u_int32_t reqid, u_int32_t spi, host_t *remote) +{ + mapping_data_t *data; + DBG(DBG_CONTROL, + DBG_log("creating mapping event for SA with SPI %.8x and reqid {%u}", + spi, reqid)); + INIT(data, + .reqid = reqid, + .spi = spi, + .new_end = *(ip_address*)remote->get_sockaddr(remote), + ); + pluto->events->queue(pluto->events, (void*)handle_mapping, data, free); + return TRUE; +} +void init_kernel(void) +{ /* register SA types that we can negotiate */ - can_do_IPcomp = FALSE; /* until we get a response from KLIPS */ - kernel_ops->pfkey_register(); + can_do_IPcomp = FALSE; /* until we get a response from the kernel */ + pfkey_register(); + + INIT(kernel_handler, + .acquire = _acquire, + .mapping = _mapping, + ); + hydra->kernel_interface->add_listener(hydra->kernel_interface, + kernel_handler); +} - if (!kernel_ops->policy_lifetime) - { - event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL); - } -#endif +void kernel_finalize() +{ + hydra->kernel_interface->remove_listener(hydra->kernel_interface, + kernel_handler); + free(kernel_handler); } /* Note: install_inbound_ipsec_sa is only used by the Responder. @@ -2482,13 +1664,8 @@ bool install_inbound_ipsec_sa(struct state *st) return FALSE; } -#ifdef KLIPS /* (attempt to) actually set up the SAs */ return setup_half_ipsec_sa(st, TRUE); -#else /* !KLIPS */ - DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa()")); - return TRUE; -#endif /* !KLIPS */ } /* Install a route and then a prospective shunt eroute or an SA group eroute. @@ -2496,11 +1673,8 @@ bool install_inbound_ipsec_sa(struct state *st) * Any SA Group must have already been created. * On failure, steps will be unwound. */ -bool route_and_eroute(connection_t *c USED_BY_KLIPS, - struct spd_route *sr USED_BY_KLIPS, - struct state *st USED_BY_KLIPS) +bool route_and_eroute(connection_t *c, struct spd_route *sr, struct state *st) { -#ifdef KLIPS struct spd_route *esr; struct spd_route *rosr; connection_t *ero /* who, if anyone, owns our eroute? */ @@ -2510,7 +1684,6 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, , route_installed = FALSE; connection_t *ero_top; - struct bare_shunt **bspp; DBG(DBG_CONTROLMORE, DBG_log("route_and_eroute with c: %s (next: %s) ero:%s esr:{%p} ro:%s rosr:{%p} and state: %lu" @@ -2537,15 +1710,9 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, break; #endif - bspp = (ero == NULL) - ? bare_shunt_ptr(&sr->this.client, &sr->that.client, sr->this.protocol) - : NULL; - /* install the eroute */ - passert(bspp == NULL || ero == NULL); /* only one non-NULL */ - - if (bspp != NULL || ero != NULL) + if (ero != NULL) { /* We're replacing an eroute */ @@ -2571,7 +1738,6 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, && samesubnet(&esr->that.client, &sr->that.client)); } #endif - /* remember to free bspp iff we make it out of here alive */ } else { @@ -2601,7 +1767,7 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, */ firewall_notified = st == NULL /* not a tunnel eroute */ || sr->eroute_owner != SOS_NOBODY /* already notified */ - || do_command(c, sr, "up"); /* go ahead and notify */ + || do_command(c, sr, st, "up"); /* go ahead and notify */ } /* install the route */ @@ -2616,8 +1782,8 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, else if (ro == NULL) { /* a new route: no deletion required, but preparation is */ - (void) do_command(c, sr, "prepare"); /* just in case; ignore failure */ - route_installed = do_command(c, sr, "route"); + (void) do_command(c, sr, st, "prepare"); /* just in case; ignore failure */ + route_installed = do_command(c, sr, st, "route"); } else if (routed(sr->routing) || routes_agree(ro, c)) { @@ -2636,13 +1802,13 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, */ if (sameaddr(&sr->this.host_nexthop, &esr->this.host_nexthop)) { - (void) do_command(ro, sr, "unroute"); - route_installed = do_command(c, sr, "route"); + (void) do_command(ro, sr, st, "unroute"); + route_installed = do_command(c, sr, st, "route"); } else { - route_installed = do_command(c, sr, "route"); - (void) do_command(ro, sr, "unroute"); + route_installed = do_command(c, sr, st, "route"); + (void) do_command(ro, sr, st, "unroute"); } /* record unrouting */ @@ -2663,11 +1829,7 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, { /* Success! */ - if (bspp != NULL) - { - free_bare_shunt(bspp); - } - else if (ero != NULL && ero != c) + if (ero != NULL && ero != c) { /* check if ero is an ancestor of c. */ connection_t *ero2; @@ -2713,7 +1875,7 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, { /* Failure! Unwind our work. */ if (firewall_notified && sr->eroute_owner == SOS_NOBODY) - (void) do_command(c, sr, "down"); + (void) do_command(c, sr, st, "down"); if (eroute_installed) { @@ -2721,28 +1883,7 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, * Since there is nothing much to be done if the restoration * fails, ignore success or failure. */ - if (bspp != NULL) - { - /* Restore old bare_shunt. - * I don't think that this case is very likely. - * Normally a bare shunt would have been assigned - * to a connection before we've gotten this far. - */ - struct bare_shunt *bs = *bspp; - - (void) raw_eroute(&bs->said.dst /* should be useless */ - , &bs->ours - , &bs->said.dst /* should be useless */ - , &bs->his - , bs->said.spi /* network order */ - , SA_INT - , SADB_X_SATYPE_INT - , 0 - , null_proto_info - , SHUNT_PATIENCE - , ERO_REPLACE, "restore"); - } - else if (ero != NULL) + if (ero != NULL) { /* restore ero's former glory */ if (esr->eroute_owner == SOS_NOBODY) @@ -2781,14 +1922,10 @@ bool route_and_eroute(connection_t *c USED_BY_KLIPS, return FALSE; } -#else /* !KLIPS */ - return TRUE; -#endif /* !KLIPS */ } -bool install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS) +bool install_ipsec_sa(struct state *st, bool inbound_also) { -#ifdef KLIPS struct spd_route *sr; DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() for #%ld: %s" @@ -2838,21 +1975,6 @@ bool install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS) } } } -#else /* !KLIPS */ - DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() %s" - , inbound_also? "inbound and oubound" : "outbound only")); - - switch (could_route(st->st_connection)) - { - case route_easy: - case route_nearconflict: - break; - default: - return FALSE; - } - - -#endif /* !KLIPS */ return TRUE; } @@ -2861,10 +1983,8 @@ bool install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS) * we may not succeed, but we bull ahead anyway because * we cannot do anything better by recognizing failure */ -void delete_ipsec_sa(struct state *st USED_BY_KLIPS, - bool inbound_only USED_BY_KLIPS) +void delete_ipsec_sa(struct state *st, bool inbound_only) { -#ifdef KLIPS if (!inbound_only) { /* If the state is the eroute owner, we must adjust @@ -2890,7 +2010,7 @@ void delete_ipsec_sa(struct state *st USED_BY_KLIPS, sr->routing = (c->policy & POLICY_FAIL_MASK) == POLICY_FAIL_NONE ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE; - (void) do_command(c, sr, "down"); + (void) do_command(c, sr, st, "down"); if ((c->policy & POLICY_DONT_REKEY) && c->kind == CK_INSTANCE) { /* in this special case, even if the connection @@ -2911,46 +2031,41 @@ void delete_ipsec_sa(struct state *st USED_BY_KLIPS, (void) teardown_half_ipsec_sa(st, FALSE); } (void) teardown_half_ipsec_sa(st, TRUE); -#else /* !KLIPS */ - DBG(DBG_CONTROL, DBG_log("if I knew how, I'd eroute() and teardown_ipsec_sa()")); -#endif /* !KLIPS */ } -#ifdef KLIPS static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound) { connection_t *c = st->st_connection; - char text_said[SATOT_BUF]; - struct kernel_sa sa; - ip_address - src = inbound? c->spd.that.host_addr : c->spd.this.host_addr, - dst = inbound? c->spd.this.host_addr : c->spd.that.host_addr; - - ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi; - - u_int16_t - natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port, - natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port; - - set_text_said(text_said, &dst, esp_spi, SA_ESP); - - memset(&sa, 0, sizeof(sa)); - sa.spi = esp_spi; - sa.src = &src; - sa.dst = &dst; - sa.text_said = text_said; - sa.authalg = alg_info_esp_aa2sadb(st->st_esp.attrs.auth); - sa.natt_sport = natt_sport; - sa.natt_dport = natt_dport; - sa.transid = st->st_esp.attrs.transid; - - return kernel_ops->add_sa(&sa, TRUE); + host_t *host_src, *host_dst, *new_src, *new_dst; + ipsec_spi_t spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; + struct end *src = inbound ? &c->spd.that : &c->spd.this, + *dst = inbound ? &c->spd.this : &c->spd.that; + mark_t mark = inbound ? c->spd.mark_in : c->spd.mark_out; + bool result; + + host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); + host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); + + new_src = host_src->clone(host_src); + new_dst = host_dst->clone(host_dst); + new_src->set_port(new_src, src->host_port); + new_dst->set_port(new_dst, dst->host_port); + + result = hydra->kernel_interface->update_sa(hydra->kernel_interface, + spi, IPPROTO_ESP, 0 /* cpi */, host_src, host_dst, + new_src, new_dst, TRUE /* encap */, TRUE /* new_encap */, + mark) == SUCCESS; + + host_src->destroy(host_src); + host_dst->destroy(host_dst); + new_src->destroy(new_src); + new_dst->destroy(new_dst); + + return result; } -#endif -bool update_ipsec_sa (struct state *st USED_BY_KLIPS) +bool update_ipsec_sa (struct state *st) { -#ifdef KLIPS if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) { if (st->st_esp.present && ( @@ -2973,10 +2088,6 @@ bool update_ipsec_sa (struct state *st USED_BY_KLIPS) return FALSE; } return TRUE; -#else /* !KLIPS */ - DBG(DBG_CONTROL, DBG_log("if I knew how, I'd update_ipsec_sa()")); - return TRUE; -#endif /* !KLIPS */ } /* Check if there was traffic on given SA during the last idle_max @@ -2986,102 +2097,17 @@ bool update_ipsec_sa (struct state *st USED_BY_KLIPS) */ bool was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time) { - static const char procname[] = "/proc/net/ipsec_spi"; - FILE *f; - char buf[1024]; + time_t use_time; u_int bytes; int ret = TRUE; passert(st != NULL); - f = fopen(procname, "r"); - if (f == NULL) + if (get_sa_info(st, TRUE, &bytes, &use_time) && use_time != UNDEFINED_TIME) { - /* Can't open the file, perhaps were are on 26sec? */ - time_t use_time; - - if (get_sa_info(st, TRUE, &bytes, &use_time) && use_time != UNDEFINED_TIME) - { - *idle_time = time(NULL) - use_time; - ret = *idle_time >= idle_max; - } + *idle_time = time_monotonic(NULL) - use_time; + ret = *idle_time >= idle_max; } - else - { - while (f != NULL) - { - char *line; - char text_said[SATOT_BUF]; - u_int8_t proto = 0; - ip_address dst; - ip_said said; - ipsec_spi_t spi = 0; - static const char idle[] = "idle="; - - dst = st->st_connection->spd.this.host_addr; /* inbound SA */ - if (st->st_ah.present) - { - proto = SA_AH; - spi = st->st_ah.our_spi; - } - if (st->st_esp.present) - { - proto = SA_ESP; - spi = st->st_esp.our_spi; - } - - if (proto == 0 && spi == 0) - { - ret = TRUE; - break; - } - initsaid(&dst, spi, proto, &said); - satot(&said, 'x', text_said, SATOT_BUF); - - line = fgets(buf, sizeof(buf), f); - if (line == NULL) - { - /* Reached end of list */ - ret = TRUE; - break; - } - - if (strneq(line, text_said, strlen(text_said))) - { - /* we found a match, now try to find idle= */ - char *p = strstr(line, idle); - - if (p == NULL) - { - /* SAs which haven't been used yet don't have it */ - ret = TRUE; /* it didn't have traffic */ - break; - } - p += sizeof(idle)-1; - if (*p == '\0') - { - ret = TRUE; /* be paranoid */ - break; - } - if (sscanf(p, "%d", (int *) idle_time) <= 0) - { - ret = TRUE; - break; - } - if (*idle_time >= idle_max) - { - ret = TRUE; - break; - } - else - { - ret = FALSE; - break; - } - } - } - fclose(f); - } return ret; } diff --git a/src/pluto/kernel.h b/src/pluto/kernel.h index 06850abfd..1fa11c50e 100644 --- a/src/pluto/kernel.h +++ b/src/pluto/kernel.h @@ -14,10 +14,8 @@ #include "connections.h" -extern bool no_klips; /* don't actually use KLIPS */ extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */ -#ifdef KLIPS /* Declare eroute things early enough for uses. * * Flags are encoded above the low-order byte of verbs. @@ -32,8 +30,6 @@ extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */ #define ERO_DELETE SADB_X_DELFLOW #define ERO_ADD SADB_X_ADDFLOW #define ERO_REPLACE (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT)) -#define ERO_ADD_INBOUND (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) -#define ERO_DEL_INBOUND (SADB_X_DELFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) struct pfkey_proto_info { int proto; @@ -75,69 +71,6 @@ struct kernel_sa { const char *text_said; }; -struct kernel_ops { - enum { - KERNEL_TYPE_NONE, - KERNEL_TYPE_KLIPS, - KERNEL_TYPE_LINUX, - } type; - bool inbound_eroute; - bool policy_lifetime; - int *async_fdp; - - void (*init)(void); - void (*pfkey_register)(void); - void (*pfkey_register_response)(const struct sadb_msg *msg); - void (*process_queue)(void); - void (*process_msg)(void); - bool (*raw_eroute)(const ip_address *this_host, - const ip_subnet *this_client, - const ip_address *that_host, - const ip_subnet *that_client, - ipsec_spi_t spi, - unsigned int satype, - unsigned int transport_proto, - const struct pfkey_proto_info *proto_info, - time_t use_lifetime, - unsigned int op, - const char *text_said); - bool (*get_policy)(const struct kernel_sa *sa, bool inbound, - time_t *use_time); - bool (*add_sa)(const struct kernel_sa *sa, bool replace); - bool (*grp_sa)(const struct kernel_sa *sa_outer, - const struct kernel_sa *sa_inner); - bool (*del_sa)(const struct kernel_sa *sa); - bool (*get_sa)(const struct kernel_sa *sa, u_int *bytes); - ipsec_spi_t (*get_spi)(const ip_address *src, - const ip_address *dst, - int proto, - bool tunnel_mode, - unsigned reqid, - ipsec_spi_t min, - ipsec_spi_t max, - const char *text_said); -}; - - -extern const struct kernel_ops *kernel_ops; - -/* information from /proc/net/ipsec_eroute */ - -struct eroute_info { - unsigned long count; - ip_subnet ours; - ip_subnet his; - ip_address dst; - ip_said said; - int transport_proto; - struct eroute_info *next; -}; - -extern struct eroute_info *orphaned_holds; - -extern void show_shunt_status(void); -#endif - /* A netlink header defines EM_MAXRELSPIS, the max number of SAs in a group. * Is there a PF_KEY equivalent? */ @@ -151,22 +84,11 @@ extern void record_and_initiate_opportunistic(const ip_subnet * , const char *why); extern void init_kernel(void); - -extern void scan_proc_shunts(void); +extern void kernel_finalize(void); extern bool trap_connection(struct connection *c); extern void unroute_connection(struct connection *c); -extern bool has_bare_hold(const ip_address *src, const ip_address *dst - , int transport_proto); - -extern bool replace_bare_shunt(const ip_address *src, const ip_address *dst - , policy_prio_t policy_prio - , ipsec_spi_t shunt_spi /* in host order! */ - , bool repl - , unsigned int transport_proto - , const char *why); - extern bool assign_hold(struct connection *c , struct spd_route *sr , int transport_proto diff --git a/src/pluto/kernel_alg.c b/src/pluto/kernel_alg.c index 7c2855edc..2a195cffc 100644 --- a/src/pluto/kernel_alg.c +++ b/src/pluto/kernel_alg.c @@ -105,7 +105,7 @@ const struct sadb_alg* kernel_alg_sadb_alg_get(int satype, int exttype, */ static void kernel_alg_init(void) { - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("alg_init(): memset(%p, 0, %d) memset(%p, 0, %d)", &esp_aalg, (int)sizeof (esp_aalg), &esp_ealg, (int)sizeof (esp_ealg)) @@ -121,7 +121,7 @@ static int kernel_alg_add(int satype, int exttype, struct sadb_alg *alg_p = NULL; int alg_id = sadb_alg->sadb_alg_id; - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("kernel_alg_add(): satype=%d, exttype=%d, alg_id=%d", satype, exttype, sadb_alg->sadb_alg_id) ) @@ -131,7 +131,7 @@ static int kernel_alg_add(int satype, int exttype, /* This logic "mimics" KLIPS: first algo implementation will be used */ if (alg_p->sadb_alg_id) { - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("kernel_alg_add(): discarding already setup " "satype=%d, exttype=%d, alg_id=%d", satype, exttype, sadb_alg->sadb_alg_id) @@ -172,7 +172,7 @@ bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, out: if (ret) { - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("kernel_alg_esp_enc_ok(%d,%d): " "alg_id=%d, " "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " @@ -188,7 +188,7 @@ out: } else { - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO", alg_id, key_len); ) } @@ -253,66 +253,6 @@ bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, } /** - * Load kernel_alg arrays from /proc used in manual mode from klips/utils/spi.c - */ -int kernel_alg_proc_read(void) -{ - int satype; - int supp_exttype; - int alg_id, ivlen, minbits, maxbits; - struct sadb_alg sadb_alg; - int ret; - char buf[128]; - - FILE *fp=fopen("/proc/net/pf_key_supported", "r"); - - if (!fp) - return -1; - - kernel_alg_init(); - - while (fgets(buf, sizeof(buf), fp)) - { - if (buf[0] != ' ') /* skip titles */ - continue; - - sscanf(buf, "%d %d %d %d %d %d" - ,&satype, &supp_exttype - , &alg_id, &ivlen - , &minbits, &maxbits); - - switch (satype) - { - case SADB_SATYPE_ESP: - switch(supp_exttype) - { - case SADB_EXT_SUPPORTED_AUTH: - case SADB_EXT_SUPPORTED_ENCRYPT: - sadb_alg.sadb_alg_id = alg_id; - sadb_alg.sadb_alg_ivlen = ivlen; - sadb_alg.sadb_alg_minbits = minbits; - sadb_alg.sadb_alg_maxbits = maxbits; - ret = kernel_alg_add(satype, supp_exttype, &sadb_alg); - DBG(DBG_CRYPT, - DBG_log("kernel_alg_proc_read() alg_id=%d, " - "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " - "ret=%d" - , sadb_alg.sadb_alg_id - , sadb_alg.sadb_alg_ivlen - , sadb_alg.sadb_alg_minbits - , sadb_alg.sadb_alg_maxbits - , ret) - ) - } - default: - continue; - } - } - fclose(fp); - return 0; -} - -/** * Load kernel_alg arrays pluto's SADB_REGISTER user by pluto/kernel.c */ void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen) @@ -346,7 +286,7 @@ void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen) int supp_exttype = sadb.supported->sadb_supported_exttype; int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN; - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " "sadb_msg_len=%d sadb_supported_len=%d" , satype==SADB_SATYPE_ESP? "ESP" : "AH" @@ -363,7 +303,7 @@ void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen) { kernel_alg_add(satype, supp_exttype, sadb.alg); - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " "alg[%d], exttype=%d, satype=%d, alg_id=%d, " "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " @@ -438,7 +378,7 @@ u_int kernel_alg_esp_enc_keylen(u_int alg_id) } none: - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("kernel_alg_esp_enc_keylen(): alg_id=%d, keylen=%d", alg_id, keylen) ) @@ -450,7 +390,7 @@ struct sadb_alg* kernel_alg_esp_sadb_alg(u_int alg_id) struct sadb_alg *sadb_alg = (ESP_EALG_PRESENT(alg_id)) ? &esp_ealg[alg_id] : NULL; - DBG(DBG_KLIPS, + DBG(DBG_KERNEL, DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p" , alg_id, sadb_alg) ) diff --git a/src/pluto/kernel_alg.h b/src/pluto/kernel_alg.h index 5ce8c3003..4c757db41 100644 --- a/src/pluto/kernel_alg.h +++ b/src/pluto/kernel_alg.h @@ -33,7 +33,6 @@ extern bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struc extern u_int kernel_alg_esp_enc_keylen(u_int alg_id); extern bool kernel_alg_esp_auth_ok(u_int auth, struct alg_info_esp *nfo); extern u_int kernel_alg_esp_auth_keylen(u_int auth); -extern int kernel_alg_proc_read(void); extern void kernel_alg_list(void); /* get sadb_alg for passed args */ diff --git a/src/pluto/kernel_netlink.c b/src/pluto/kernel_netlink.c deleted file mode 100644 index 75d0c98d3..000000000 --- a/src/pluto/kernel_netlink.c +++ /dev/null @@ -1,1319 +0,0 @@ -/* netlink interface to the kernel's IPsec mechanism - * Copyright (C) 2003 Herbert Xu. - * - * 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. - */ - -#if defined(linux) && defined(KERNEL26_SUPPORT) - -#include <errno.h> -#include <fcntl.h> -#include <string.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/queue.h> -#include <unistd.h> -#include <linux/xfrm.h> -#include <linux/rtnetlink.h> - -#include "kameipsec.h" - -#include <freeswan.h> -#include <pfkeyv2.h> -#include <pfkey.h> - -#include "constants.h" -#include "defs.h" -#include "kernel.h" -#include "kernel_netlink.h" -#include "kernel_pfkey.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "kernel_alg.h" - -/** required for Linux 2.6.26 kernel and later */ -#ifndef XFRM_STATE_AF_UNSPEC -#define XFRM_STATE_AF_UNSPEC 32 -#endif - -/* Minimum priority number in SPD used by pluto. */ -#define MIN_SPD_PRIORITY 1024 - -static int netlinkfd = NULL_FD; -static int netlink_bcast_fd = NULL_FD; - -#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */ - -static sparse_names xfrm_type_names = { - NE(NLMSG_NOOP), - NE(NLMSG_ERROR), - NE(NLMSG_DONE), - NE(NLMSG_OVERRUN), - - NE(XFRM_MSG_NEWSA), - NE(XFRM_MSG_DELSA), - NE(XFRM_MSG_GETSA), - - NE(XFRM_MSG_NEWPOLICY), - NE(XFRM_MSG_DELPOLICY), - NE(XFRM_MSG_GETPOLICY), - - NE(XFRM_MSG_ALLOCSPI), - NE(XFRM_MSG_ACQUIRE), - NE(XFRM_MSG_EXPIRE), - - NE(XFRM_MSG_UPDPOLICY), - NE(XFRM_MSG_UPDSA), - - NE(XFRM_MSG_POLEXPIRE), - - NE(XFRM_MSG_MAX), - - { 0, sparse_end } -}; - -#undef NE - -/* Authentication algorithms */ -static sparse_names aalg_list = { - { SADB_X_AALG_NULL, "digest_null" }, - { SADB_AALG_MD5HMAC, "md5" }, - { SADB_AALG_SHA1HMAC, "sha1" }, - { SADB_X_AALG_SHA2_256_96HMAC, "sha256" }, - { SADB_X_AALG_SHA2_256HMAC, "hmac(sha256)" }, - { SADB_X_AALG_SHA2_384HMAC, "hmac(sha384)" }, - { SADB_X_AALG_SHA2_512HMAC, "hmac(sha512)" }, - { SADB_X_AALG_RIPEMD160HMAC, "ripemd160" }, - { SADB_X_AALG_AES_XCBC_MAC, "xcbc(aes)"}, - { 0, sparse_end } -}; - -/* Encryption algorithms */ -static sparse_names ealg_list = { - { SADB_EALG_NULL, "cipher_null" }, - { SADB_EALG_DESCBC, "des" }, - { SADB_EALG_3DESCBC, "des3_ede" }, - { SADB_X_EALG_CASTCBC, "cast128" }, - { SADB_X_EALG_BLOWFISHCBC, "blowfish" }, - { SADB_X_EALG_AESCBC, "aes" }, - { SADB_X_EALG_AESCTR, "rfc3686(ctr(aes))" }, - { SADB_X_EALG_AES_CCM_ICV8, "rfc4309(ccm(aes))" }, - { SADB_X_EALG_AES_CCM_ICV12, "rfc4309(ccm(aes))" }, - { SADB_X_EALG_AES_CCM_ICV16, "rfc4309(ccm(aes))" }, - { SADB_X_EALG_AES_GCM_ICV8, "rfc4106(gcm(aes))" }, - { SADB_X_EALG_AES_GCM_ICV12, "rfc4106(gcm(aes))" }, - { SADB_X_EALG_AES_GCM_ICV16, "rfc4106(gcm(aes))" }, - { SADB_X_EALG_NULL_AES_GMAC, "rfc4543(gcm(aes))" }, - { SADB_X_EALG_CAMELLIACBC, "cbc(camellia)" }, - { SADB_X_EALG_SERPENTCBC, "serpent" }, - { SADB_X_EALG_TWOFISHCBC, "twofish" }, - { 0, sparse_end } -}; - -/* Compression algorithms */ -static sparse_names calg_list = { - { SADB_X_CALG_DEFLATE, "deflate" }, - { SADB_X_CALG_LZS, "lzs" }, - { SADB_X_CALG_LZJH, "lzjh" }, - { 0, sparse_end } -}; - -/** ip2xfrm - Take an IP address and convert to an xfrm. - * - * @param addr ip_address - * @param xaddr xfrm_address_t - IPv[46] Address from addr is copied here. - */ -static void ip2xfrm(const ip_address *addr, xfrm_address_t *xaddr) -{ - if (addr->u.v4.sin_family == AF_INET) - { - xaddr->a4 = addr->u.v4.sin_addr.s_addr; - } - else - { - memcpy(xaddr->a6, &addr->u.v6.sin6_addr, sizeof(xaddr->a6)); - } -} - -/** init_netlink - Initialize the netlink inferface. Opens the sockets and - * then binds to the broadcast socket. - */ -static void init_netlink(void) -{ - struct sockaddr_nl addr; - - netlinkfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); - - if (netlinkfd < 0) - { - exit_log_errno((e, "socket() in init_netlink()")); - } - if (fcntl(netlinkfd, F_SETFD, FD_CLOEXEC) != 0) - { - exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_netlink()")); - } - netlink_bcast_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); - - if (netlink_bcast_fd < 0) - { - exit_log_errno((e, "socket() for bcast in init_netlink()")); - } - if (fcntl(netlink_bcast_fd, F_SETFD, FD_CLOEXEC) != 0) - { - exit_log_errno((e, "fcntl(FD_CLOEXEC) for bcast in init_netlink()")); - } - if (fcntl(netlink_bcast_fd, F_SETFL, O_NONBLOCK) != 0) - { - exit_log_errno((e, "fcntl(O_NONBLOCK) for bcast in init_netlink()")); - } - addr.nl_family = AF_NETLINK; - addr.nl_pid = getpid(); - addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; - if (bind(netlink_bcast_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) - { - exit_log_errno((e, "Failed to bind bcast socket in init_netlink()")); - } -} - -/** send_netlink_msg - * - * @param hdr - Data to be sent. - * @param rbuf - Return Buffer - contains data returned from the send. - * @param rbuf_len - Length of rbuf - * @param description - String - user friendly description of what is - * being attempted. Used for diagnostics - * @param text_said - String - * @return bool True if the message was succesfully sent. - */ -static bool send_netlink_msg(struct nlmsghdr *hdr, struct nlmsghdr *rbuf, - size_t rbuf_len, const char *description, - const char *text_said) -{ - struct { - struct nlmsghdr n; - struct nlmsgerr e; - char data[1024]; - } rsp; - - size_t len; - ssize_t r; - struct sockaddr_nl addr; - static uint32_t seq; - - if (no_klips) - { - return TRUE; - } - - hdr->nlmsg_seq = ++seq; - len = hdr->nlmsg_len; - do { - r = write(netlinkfd, hdr, len); - } - while (r < 0 && errno == EINTR); - - if (r < 0) - { - log_errno((e - , "netlink write() of %s message" - " for %s %s failed" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said)); - return FALSE; - } - else if ((size_t)r != len) - { - loglog(RC_LOG_SERIOUS - , "ERROR: netlink write() of %s message" - " for %s %s truncated: %ld instead of %lu" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said - , (long)r, (unsigned long)len); - return FALSE; - } - - for (;;) - { - socklen_t alen; - - alen = sizeof(addr); - r = recvfrom(netlinkfd, &rsp, sizeof(rsp), 0 - , (struct sockaddr *)&addr, &alen); - if (r < 0) - { - if (errno == EINTR) - { - continue; - } - log_errno((e - , "netlink recvfrom() of response to our %s message" - " for %s %s failed" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said)); - return FALSE; - } - else if ((size_t) r < sizeof(rsp.n)) - { - plog("netlink read truncated message: %ld bytes; ignore message" - , (long) r); - continue; - } - else if (addr.nl_pid != 0) - { - /* not for us: ignore */ - DBG(DBG_KLIPS, - DBG_log("netlink: ignoring %s message from process %u" - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type) - , addr.nl_pid)); - continue; - } - else if (rsp.n.nlmsg_seq != seq) - { - DBG(DBG_KLIPS, - DBG_log("netlink: ignoring out of sequence (%u/%u) message %s" - , rsp.n.nlmsg_seq, seq - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type))); - continue; - } - break; - } - - if (rsp.n.nlmsg_len > (size_t) r) - { - loglog(RC_LOG_SERIOUS - , "netlink recvfrom() of response to our %s message" - " for %s %s was truncated: %ld instead of %lu" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said - , (long) len, (unsigned long) rsp.n.nlmsg_len); - return FALSE; - } - else if (rsp.n.nlmsg_type != NLMSG_ERROR - && (rbuf && rsp.n.nlmsg_type != rbuf->nlmsg_type)) - { - loglog(RC_LOG_SERIOUS - , "netlink recvfrom() of response to our %s message" - " for %s %s was of wrong type (%s)" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)); - return FALSE; - } - else if (rbuf) - { - if ((size_t) r > rbuf_len) - { - loglog(RC_LOG_SERIOUS - , "netlink recvfrom() of response to our %s message" - " for %s %s was too long: %ld > %lu" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said - , (long)r, (unsigned long)rbuf_len); - return FALSE; - } - memcpy(rbuf, &rsp, r); - return TRUE; - } - else if (rsp.n.nlmsg_type == NLMSG_ERROR && rsp.e.error) - { - loglog(RC_LOG_SERIOUS - , "ERROR: netlink response for %s %s included errno %d: %s" - , description, text_said - , -rsp.e.error - , strerror(-rsp.e.error)); - return FALSE; - } - - return TRUE; -} - -/** netlink_policy - - * - * @param hdr - Data to check - * @param enoent_ok - Boolean - OK or not OK. - * @param text_said - String - * @return boolean - */ -static bool netlink_policy(struct nlmsghdr *hdr, bool enoent_ok, - const char *text_said) -{ - struct { - struct nlmsghdr n; - struct nlmsgerr e; - char data[1024]; - } rsp; - int error; - - rsp.n.nlmsg_type = NLMSG_ERROR; - if (!send_netlink_msg(hdr, &rsp.n, sizeof(rsp), "policy", text_said)) - { - return FALSE; - } - - error = -rsp.e.error; - if (!error) - { - return TRUE; - } - - if (error == ENOENT && enoent_ok) - { - return TRUE; - } - - loglog(RC_LOG_SERIOUS - , "ERROR: netlink %s response for flow %s included errno %d: %s" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , text_said - , error - , strerror(error)); - return FALSE; -} - -/** netlink_raw_eroute - * - * @param this_host ip_address - * @param this_client ip_subnet - * @param that_host ip_address - * @param that_client ip_subnet - * @param spi - * @param proto int (Currently unused) Contains protocol (u=tcp, 17=udp, etc...) - * @param transport_proto int (Currently unused) 0=tunnel, 1=transport - * @param satype int - * @param proto_info - * @param lifetime (Currently unused) - * @param ip int - * @return boolean True if successful - */ -static bool netlink_raw_eroute(const ip_address *this_host - , const ip_subnet *this_client - , const ip_address *that_host - , const ip_subnet *that_client - , ipsec_spi_t spi - , unsigned int satype - , unsigned int transport_proto - , const struct pfkey_proto_info *proto_info - , time_t use_lifetime UNUSED - , unsigned int op - , const char *text_said) -{ - struct { - struct nlmsghdr n; - union { - struct xfrm_userpolicy_info p; - struct xfrm_userpolicy_id id; - } u; - char data[1024]; - } req; - int shift; - int dir; - int family; - int policy; - bool ok; - bool enoent_ok; - - policy = IPSEC_POLICY_IPSEC; - - if (satype == SADB_X_SATYPE_INT) - { - /* shunt route */ - switch (ntohl(spi)) - { - case SPI_PASS: - policy = IPSEC_POLICY_NONE; - break; - case SPI_DROP: - case SPI_REJECT: - default: - policy = IPSEC_POLICY_DISCARD; - break; - case SPI_TRAP: - case SPI_TRAPSUBNET: - case SPI_HOLD: - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - return TRUE; - } - break; - } - } - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - - family = that_client->addr.u.v4.sin_family; - shift = (family == AF_INET) ? 5 : 7; - - req.u.p.sel.sport = portof(&this_client->addr); - req.u.p.sel.dport = portof(&that_client->addr); - req.u.p.sel.sport_mask = (req.u.p.sel.sport) ? ~0:0; - req.u.p.sel.dport_mask = (req.u.p.sel.dport) ? ~0:0; - ip2xfrm(&this_client->addr, &req.u.p.sel.saddr); - ip2xfrm(&that_client->addr, &req.u.p.sel.daddr); - req.u.p.sel.prefixlen_s = this_client->maskbits; - req.u.p.sel.prefixlen_d = that_client->maskbits; - req.u.p.sel.proto = transport_proto; - req.u.p.sel.family = family; - - dir = XFRM_POLICY_OUT; - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - dir = XFRM_POLICY_IN; - } - - if ((op & ERO_MASK) == ERO_DELETE) - { - req.u.id.dir = dir; - req.n.nlmsg_type = XFRM_MSG_DELPOLICY; - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.id))); - } - else - { - int src, dst; - - req.u.p.dir = dir; - - src = req.u.p.sel.prefixlen_s; - dst = req.u.p.sel.prefixlen_d; - if (dir != XFRM_POLICY_OUT) { - src = req.u.p.sel.prefixlen_d; - dst = req.u.p.sel.prefixlen_s; - } - req.u.p.priority = MIN_SPD_PRIORITY - + (((2 << shift) - src) << shift) - + (2 << shift) - dst; - - req.u.p.action = XFRM_POLICY_ALLOW; - if (policy == IPSEC_POLICY_DISCARD) - { - req.u.p.action = XFRM_POLICY_BLOCK; - } - req.u.p.lft.soft_use_expires_seconds = use_lifetime; - req.u.p.lft.soft_byte_limit = XFRM_INF; - req.u.p.lft.soft_packet_limit = XFRM_INF; - req.u.p.lft.hard_byte_limit = XFRM_INF; - req.u.p.lft.hard_packet_limit = XFRM_INF; - - req.n.nlmsg_type = XFRM_MSG_NEWPOLICY; - if (op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT)) - { - req.n.nlmsg_type = XFRM_MSG_UPDPOLICY; - } - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.p))); - } - - if (policy == IPSEC_POLICY_IPSEC && (op & ERO_MASK) != ERO_DELETE) - { - struct rtattr *attr; - struct xfrm_user_tmpl tmpl[4]; - int i; - - memset(tmpl, 0, sizeof(tmpl)); - for (i = 0; proto_info[i].proto; i++) - { - tmpl[i].reqid = proto_info[i].reqid; - tmpl[i].id.proto = proto_info[i].proto; - tmpl[i].optional = - proto_info[i].proto == IPPROTO_COMP && dir != XFRM_POLICY_OUT; - tmpl[i].aalgos = tmpl[i].ealgos = tmpl[i].calgos = ~0; - tmpl[i].family = that_host->u.v4.sin_family; - tmpl[i].mode = - proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - if (!tmpl[i].mode) - { - continue; - } - - ip2xfrm(this_host, &tmpl[i].saddr); - ip2xfrm(that_host, &tmpl[i].id.daddr); - } - - attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); - attr->rta_type = XFRMA_TMPL; - attr->rta_len = i * sizeof(tmpl[0]); - memcpy(RTA_DATA(attr), tmpl, attr->rta_len); - attr->rta_len = RTA_LENGTH(attr->rta_len); - req.n.nlmsg_len += attr->rta_len; - } - - enoent_ok = FALSE; - if (op == ERO_DEL_INBOUND) - { - enoent_ok = TRUE; - } - else if (op == ERO_DELETE && ntohl(spi) == SPI_HOLD) - { - enoent_ok = TRUE; - } - - ok = netlink_policy(&req.n, enoent_ok, text_said); - switch (dir) - { - case XFRM_POLICY_IN: - if (req.n.nlmsg_type == XFRM_MSG_DELPOLICY) - { - req.u.id.dir = XFRM_POLICY_FWD; - } - else if (!ok) - { - break; - } - else if (proto_info[0].encapsulation != ENCAPSULATION_MODE_TUNNEL - && satype != SADB_X_SATYPE_INT) - { - break; - } - else - { - req.u.p.dir = XFRM_POLICY_FWD; - } - ok &= netlink_policy(&req.n, enoent_ok, text_said); - break; - } - - return ok; -} - -/** netlink_add_sa - Add an SA into the kernel SPDB via netlink - * - * @param sa Kernel SA to add/modify - * @param replace boolean - true if this replaces an existing SA - * @return bool True if successfull - */ -static bool netlink_add_sa(const struct kernel_sa *sa, bool replace) -{ - struct { - struct nlmsghdr n; - struct xfrm_usersa_info p; - char data[1024]; - } req; - struct rtattr *attr; - u_int16_t icv_size = 64; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.n.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; - - ip2xfrm(sa->src, &req.p.saddr); - ip2xfrm(sa->dst, &req.p.id.daddr); - - req.p.id.spi = sa->spi; - req.p.id.proto = satype2proto(sa->satype); - req.p.family = sa->src->u.v4.sin_family; - if (sa->encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - req.p.mode = XFRM_MODE_TUNNEL; - req.p.flags |= XFRM_STATE_AF_UNSPEC; - } - else - { - req.p.mode = XFRM_MODE_TRANSPORT; - } - req.p.replay_window = sa->replay_window; - req.p.reqid = sa->reqid; - req.p.lft.soft_byte_limit = XFRM_INF; - req.p.lft.soft_packet_limit = XFRM_INF; - req.p.lft.hard_byte_limit = XFRM_INF; - req.p.lft.hard_packet_limit = XFRM_INF; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.p))); - - attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); - - if (sa->authalg) - { - const char *name; - - name = sparse_name(aalg_list, sa->authalg); - if (!name) - { - loglog(RC_LOG_SERIOUS, "unknown authentication algorithm: %u" - , sa->authalg); - return FALSE; - } - DBG(DBG_CRYPT, - DBG_log("configured authentication algorithm %s with key size %d", - enum_show(&auth_alg_names, sa->authalg), - sa->authkeylen * BITS_PER_BYTE) - ) - - if (sa->authalg == SADB_X_AALG_SHA2_256HMAC) - { - struct xfrm_algo_auth algo; - - /* the kernel uses SHA256 with 96 bit truncation by default, - * use specified truncation size supported by newer kernels */ - strcpy(algo.alg_name, name); - algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE; - algo.alg_trunc_len = 128; - - attr->rta_type = XFRMA_ALG_AUTH_TRUNC; - attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen); - - memcpy(RTA_DATA(attr), &algo, sizeof(algo)); - memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->authkey - , sa->authkeylen); - } - else - { - struct xfrm_algo algo; - - strcpy(algo.alg_name, name); - algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE; - - attr->rta_type = XFRMA_ALG_AUTH; - attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen); - - memcpy(RTA_DATA(attr), &algo, sizeof(algo)); - memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->authkey - , sa->authkeylen); - } - req.n.nlmsg_len += attr->rta_len; - attr = (struct rtattr *)((char *)attr + attr->rta_len); - } - - switch (sa->encalg) - { - case SADB_EALG_NONE: - /* no encryption */ - break; - case SADB_X_EALG_AES_CCM_ICV16: - case SADB_X_EALG_AES_GCM_ICV16: - case SADB_X_EALG_NULL_AES_GMAC: - icv_size += 32; - /* FALL */ - case SADB_X_EALG_AES_CCM_ICV12: - case SADB_X_EALG_AES_GCM_ICV12: - icv_size += 32; - /* FALL */ - case SADB_X_EALG_AES_CCM_ICV8: - case SADB_X_EALG_AES_GCM_ICV8: - { - struct xfrm_algo_aead *algo; - const char *name; - - name = sparse_name(ealg_list, sa->encalg); - if (!name) - { - loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u", - sa->encalg); - return FALSE; - } - DBG(DBG_CRYPT, - DBG_log("configured esp encryption algorithm %s with key size %d", - enum_show(&esp_transform_names, sa->encalg), - sa->enckeylen * BITS_PER_BYTE) - ) - attr->rta_type = XFRMA_ALG_AEAD; - attr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + sa->enckeylen); - req.n.nlmsg_len += attr->rta_len; - - algo = (struct xfrm_algo_aead*)RTA_DATA(attr); - algo->alg_key_len = sa->enckeylen * BITS_PER_BYTE; - algo->alg_icv_len = icv_size; - strcpy(algo->alg_name, name); - memcpy(algo->alg_key, sa->enckey, sa->enckeylen); - - attr = (struct rtattr *)((char *)attr + attr->rta_len); - break; - } - default: - { - struct xfrm_algo *algo; - const char *name; - - name = sparse_name(ealg_list, sa->encalg); - if (!name) - { - loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u", - sa->encalg); - return FALSE; - } - DBG(DBG_CRYPT, - DBG_log("configured esp encryption algorithm %s with key size %d", - enum_show(&esp_transform_names, sa->encalg), - sa->enckeylen * BITS_PER_BYTE) - ) - attr->rta_type = XFRMA_ALG_CRYPT; - attr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + sa->enckeylen); - req.n.nlmsg_len += attr->rta_len; - - algo = (struct xfrm_algo*)RTA_DATA(attr); - algo->alg_key_len = sa->enckeylen * BITS_PER_BYTE; - strcpy(algo->alg_name, name); - memcpy(algo->alg_key, sa->enckey, sa->enckeylen); - - attr = (struct rtattr *)((char *)attr + attr->rta_len); - } - } - - if (sa->compalg) - { - struct xfrm_algo algo; - const char *name; - - name = sparse_name(calg_list, sa->compalg); - if (!name) - { - loglog(RC_LOG_SERIOUS, "unknown compression algorithm: %u" - , sa->compalg); - return FALSE; - } - - strcpy(algo.alg_name, name); - algo.alg_key_len = 0; - - attr->rta_type = XFRMA_ALG_COMP; - attr->rta_len = RTA_LENGTH(sizeof(algo)); - - memcpy(RTA_DATA(attr), &algo, sizeof(algo)); - - req.n.nlmsg_len += attr->rta_len; - attr = (struct rtattr *)((char *)attr + attr->rta_len); - } - - if (sa->natt_type) - { - struct xfrm_encap_tmpl natt; - - natt.encap_type = sa->natt_type; - natt.encap_sport = ntohs(sa->natt_sport); - natt.encap_dport = ntohs(sa->natt_dport); - memset (&natt.encap_oa, 0, sizeof (natt.encap_oa)); - - attr->rta_type = XFRMA_ENCAP; - attr->rta_len = RTA_LENGTH(sizeof(natt)); - - memcpy(RTA_DATA(attr), &natt, sizeof(natt)); - - req.n.nlmsg_len += attr->rta_len; - attr = (struct rtattr *)((char *)attr + attr->rta_len); - } - - return send_netlink_msg(&req.n, NULL, 0, "Add SA", sa->text_said); -} - -/** netlink_del_sa - Delete an SA from the Kernel - * - * @param sa Kernel SA to be deleted - * @return bool True if successfull - */ -static bool netlink_del_sa(const struct kernel_sa *sa) -{ - struct { - struct nlmsghdr n; - struct xfrm_usersa_id id; - char data[1024]; - } req; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.n.nlmsg_type = XFRM_MSG_DELSA; - - ip2xfrm(sa->dst, &req.id.daddr); - - req.id.spi = sa->spi; - req.id.family = sa->src->u.v4.sin_family; - req.id.proto = sa->proto; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); - - return send_netlink_msg(&req.n, NULL, 0, "Del SA", sa->text_said); -} - -static bool netlink_error(const char *req_type, const struct nlmsghdr *n, - const struct nlmsgerr *e, int rsp_size) -{ - if (n->nlmsg_type == NLMSG_ERROR) - { - DBG(DBG_KLIPS, - DBG_log("%s returned with errno %d: %s" - , req_type - , -e->error - , strerror(-e->error)) - ) - return TRUE; - } - if (n->nlmsg_len < NLMSG_LENGTH(rsp_size)) - { - plog("%s returned message with length %lu < %lu bytes" - , req_type - , (unsigned long) n->nlmsg_len - , (unsigned long) rsp_size); - return TRUE; - } - return FALSE; -} - -static bool netlink_get_policy(const struct kernel_sa *sa, bool inbound, - time_t *use_time) -{ - struct { - struct nlmsghdr n; - struct xfrm_userpolicy_id id; - } req; - - struct { - struct nlmsghdr n; - union { - struct nlmsgerr e; - struct xfrm_userpolicy_info info; - } u; - char data[1024]; - } rsp; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_GETPOLICY; - - req.id.sel.sport = portof(&sa->src_client->addr); - req.id.sel.dport = portof(&sa->dst_client->addr); - req.id.sel.sport_mask = (req.id.sel.sport) ? ~0:0; - req.id.sel.dport_mask = (req.id.sel.dport) ? ~0:0; - ip2xfrm(&sa->src_client->addr, &req.id.sel.saddr); - ip2xfrm(&sa->dst_client->addr, &req.id.sel.daddr); - req.id.sel.prefixlen_s = sa->src_client->maskbits; - req.id.sel.prefixlen_d = sa->dst_client->maskbits; - req.id.sel.proto = sa->transport_proto; - req.id.sel.family = sa->dst_client->addr.u.v4.sin_family; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); - rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY; - - req.id.dir = (inbound)? XFRM_POLICY_IN:XFRM_POLICY_OUT; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) - { - return FALSE; - } - if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) - { - return FALSE; - } - *use_time = (time_t)rsp.u.info.curlft.use_time; - - if (inbound && sa->encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - time_t use_time_fwd; - - req.id.dir = XFRM_POLICY_FWD; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) - { - return FALSE; - } - if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) - { - return FALSE; - } - use_time_fwd = (time_t)rsp.u.info.curlft.use_time; - *use_time = (*use_time > use_time_fwd)? *use_time : use_time_fwd; - } - return TRUE; -} - - -/** netlink_get_sa - Get information about an SA from the Kernel - * - * @param sa Kernel SA to be queried - * @return bool True if successfull - */ -static bool netlink_get_sa(const struct kernel_sa *sa, u_int *bytes) -{ - struct { - struct nlmsghdr n; - struct xfrm_usersa_id id; - } req; - - struct { - struct nlmsghdr n; - union { - struct nlmsgerr e; - struct xfrm_usersa_info info; - } u; - char data[1024]; - } rsp; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_GETSA; - - ip2xfrm(sa->dst, &req.id.daddr); - - req.id.spi = sa->spi; - req.id.family = sa->src->u.v4.sin_family; - req.id.proto = sa->proto; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); - rsp.n.nlmsg_type = XFRM_MSG_NEWSA; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SA", sa->text_said)) - { - return FALSE; - } - if (netlink_error("XFRM_MSG_GETSA", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) - { - return FALSE; - } - *bytes = (u_int) rsp.u.info.curlft.bytes; - return TRUE; -} - -static void linux_pfkey_register_response(const struct sadb_msg *msg) -{ - switch (msg->sadb_msg_satype) - { - case SADB_SATYPE_ESP: -#ifndef NO_KERNEL_ALG - kernel_alg_register_pfkey(msg, msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); -#endif - break; - case SADB_X_SATYPE_IPCOMP: - can_do_IPcomp = TRUE; - break; - default: - break; - } -} - -/** linux_pfkey_register - Register via PFKEY our capabilities - * - */ -static void linux_pfkey_register(void) -{ - pfkey_register_proto(SADB_SATYPE_AH, "AH"); - pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); - pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP"); - pfkey_close(); -} - -/** Create ip_address out of xfrm_address_t. - * - * @param family - * @param src xfrm formatted IP address - * @param dst ip_address formatted destination - * @return err_t NULL if okay, otherwise an error - */ -static err_t xfrm_to_ip_address(unsigned family, const xfrm_address_t *src, - ip_address *dst) -{ - switch (family) - { - case AF_INET: /* IPv4 */ - case AF_UNSPEC: /* Unspecified, we assume IPv4 */ - initaddr((const void *) &src->a4, sizeof(src->a4), AF_INET, dst); - return NULL; - case AF_INET6: /* IPv6 */ - initaddr((const void *) &src->a6, sizeof(src->a6), AF_INET6, dst); - return NULL; - default: - return "unknown address family"; - } -} - -/* Create a pair of ip_address's out of xfrm_sel. - * - * @param sel xfrm selector - * @param src ip_address formatted source - * @param dst ip_address formatted destination - * @return err_t NULL if okay, otherwise an error - */ -static err_t xfrm_sel_to_ip_pair(const struct xfrm_selector *sel, - ip_address *src, ip_address *dst) -{ - int family; - err_t ugh; - - family = sel->family; - - if ((ugh = xfrm_to_ip_address(family, &sel->saddr, src)) - || (ugh = xfrm_to_ip_address(family, &sel->daddr, dst))) - { - return ugh; - } - - /* family has been verified in xfrm_to_ip_address. */ - if (family == AF_INET) - { - src->u.v4.sin_port = sel->sport; - dst->u.v4.sin_port = sel->dport; - } - else - { - src->u.v6.sin6_port = sel->sport; - dst->u.v6.sin6_port = sel->dport; - } - - return NULL; -} - -static void netlink_acquire(struct nlmsghdr *n) -{ - struct xfrm_user_acquire *acquire; - ip_address src, dst; - ip_subnet ours, his; - unsigned transport_proto; - err_t ugh = NULL; - - if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*acquire))) - { - plog("netlink_acquire got message with length %lu < %lu bytes; ignore message" - , (unsigned long) n->nlmsg_len - , (unsigned long) sizeof(*acquire)); - return; - } - - acquire = NLMSG_DATA(n); - transport_proto = acquire->sel.proto; - - /* XXX also the type of src/dst should be checked to make sure - * that they aren't v4 to v6 or something goofy - */ - - if (!(ugh = xfrm_sel_to_ip_pair(&acquire->sel, &src, &dst)) - && !(ugh = addrtosubnet(&src, &ours)) - && !(ugh = addrtosubnet(&dst, &his))) - { - record_and_initiate_opportunistic(&ours, &his, transport_proto - , "%acquire-netlink"); - } - if (ugh != NULL) - { - plog("XFRM_MSG_ACQUIRE message from kernel malformed: %s", ugh); - } -} - -static void netlink_shunt_expire(struct xfrm_userpolicy_info *pol) -{ - ip_address src, dst; - unsigned transport_proto; - err_t ugh = NULL; - - transport_proto = pol->sel.proto; - - if (!(ugh = xfrm_sel_to_ip_pair(&pol->sel, &src, &dst))) - { - plog("XFRM_MSG_POLEXPIRE message from kernel malformed: %s", ugh); - return; - } - - replace_bare_shunt(&src, &dst, BOTTOM_PRIO, SPI_PASS, FALSE, transport_proto - , "delete expired bare shunt"); -} - -static void netlink_policy_expire(struct nlmsghdr *n) -{ - struct xfrm_user_polexpire *upe; - struct { - struct nlmsghdr n; - struct xfrm_userpolicy_id id; - } req; - - struct { - struct nlmsghdr n; - union { - struct nlmsgerr e; - struct xfrm_userpolicy_info pol; - } u; - char data[1024]; - } rsp; - - if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*upe))) - { - plog("netlink_policy_expire got message with length %lu < %lu bytes; ignore message" - , (unsigned long) n->nlmsg_len - , (unsigned long) sizeof(*upe)); - return; - } - - upe = NLMSG_DATA(n); - req.id.dir = upe->pol.dir; - req.id.index = upe->pol.index; - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_GETPOLICY; - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); - - rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) - { - return; - } - if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.pol))) - { - return; - } - if (req.id.index != rsp.u.pol.index) - { - DBG(DBG_KLIPS, - DBG_log("netlink_policy_expire: policy was replaced: " - "dir=%d, oldindex=%d, newindex=%d" - , req.id.dir, req.id.index, rsp.u.pol.index)); - return; - } - - if (upe->pol.curlft.add_time != rsp.u.pol.curlft.add_time) - { - DBG(DBG_KLIPS, - DBG_log("netlink_policy_expire: policy was replaced " - " and you have won the lottery: " - "dir=%d, index=%d" - , req.id.dir, req.id.index)); - return; - } - - switch (upe->pol.dir) - { - case XFRM_POLICY_OUT: - netlink_shunt_expire(&rsp.u.pol); - break; - } -} - -static bool netlink_get(void) -{ - struct { - struct nlmsghdr n; - char data[1024]; - } rsp; - ssize_t r; - struct sockaddr_nl addr; - socklen_t alen; - - alen = sizeof(addr); - r = recvfrom(netlink_bcast_fd, &rsp, sizeof(rsp), 0 - , (struct sockaddr *)&addr, &alen); - if (r < 0) - { - if (errno == EAGAIN) - return FALSE; - if (errno != EINTR) - log_errno((e, "recvfrom() failed in netlink_get")); - return TRUE; - } - else if ((size_t) r < sizeof(rsp.n)) - { - plog("netlink_get read truncated message: %ld bytes; ignore message" - , (long) r); - return TRUE; - } - else if (addr.nl_pid != 0) - { - /* not for us: ignore */ - DBG(DBG_KLIPS, - DBG_log("netlink_get: ignoring %s message from process %u" - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type) - , addr.nl_pid)); - return TRUE; - } - else if ((size_t) r != rsp.n.nlmsg_len) - { - plog("netlink_get read message with length %ld that doesn't equal nlmsg_len %lu bytes; ignore message" - , (long) r - , (unsigned long) rsp.n.nlmsg_len); - return TRUE; - } - - DBG(DBG_KLIPS, - DBG_log("netlink_get: %s message" - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type))); - - switch (rsp.n.nlmsg_type) - { - case XFRM_MSG_ACQUIRE: - netlink_acquire(&rsp.n); - break; - case XFRM_MSG_POLEXPIRE: - netlink_policy_expire(&rsp.n); - break; - default: - /* ignored */ - break; - } - - return TRUE; -} - -static void netlink_process_msg(void) -{ - while (netlink_get()); -} - -static ipsec_spi_t netlink_get_spi(const ip_address *src, const ip_address *dst, - int proto, bool tunnel_mode, unsigned reqid, - ipsec_spi_t min, ipsec_spi_t max, - const char *text_said) -{ - struct { - struct nlmsghdr n; - struct xfrm_userspi_info spi; - } req; - - struct { - struct nlmsghdr n; - union { - struct nlmsgerr e; - struct xfrm_usersa_info sa; - } u; - char data[1024]; - } rsp; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_ALLOCSPI; - - ip2xfrm(src, &req.spi.info.saddr); - ip2xfrm(dst, &req.spi.info.id.daddr); - req.spi.info.mode = tunnel_mode; - req.spi.info.reqid = reqid; - req.spi.info.id.proto = proto; - req.spi.info.family = src->u.v4.sin_family; - req.spi.min = min; - req.spi.max = max; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.spi))); - rsp.n.nlmsg_type = XFRM_MSG_NEWSA; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SPI", text_said)) - { - return 0; - } - if (netlink_error("XFRM_MSG_ALLOCSPI", &rsp.n, &rsp.u.e, sizeof(rsp.u.sa))) - { - return 0; - } - DBG(DBG_KLIPS, - DBG_log("netlink_get_spi: allocated 0x%x for %s" - , ntohl(rsp.u.sa.id.spi), text_said)); - return rsp.u.sa.id.spi; -} - -const struct kernel_ops linux_kernel_ops = { - type: KERNEL_TYPE_LINUX, - inbound_eroute: 1, - policy_lifetime: 1, - async_fdp: &netlink_bcast_fd, - - init: init_netlink, - pfkey_register: linux_pfkey_register, - pfkey_register_response: linux_pfkey_register_response, - process_msg: netlink_process_msg, - raw_eroute: netlink_raw_eroute, - get_policy: netlink_get_policy, - add_sa: netlink_add_sa, - del_sa: netlink_del_sa, - get_sa: netlink_get_sa, - process_queue: NULL, - grp_sa: NULL, - get_spi: netlink_get_spi, -}; -#endif /* linux && KLIPS */ diff --git a/src/pluto/kernel_netlink.h b/src/pluto/kernel_netlink.h deleted file mode 100644 index 65163c966..000000000 --- a/src/pluto/kernel_netlink.h +++ /dev/null @@ -1,18 +0,0 @@ -/* declarations of routines that interface with the kernel's pfkey mechanism - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2003 Herbert Xu - * - * 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. - */ - -#if defined(KLIPS) && defined(linux) -extern const struct kernel_ops linux_kernel_ops; -#endif diff --git a/src/pluto/kernel_noklips.c b/src/pluto/kernel_noklips.c deleted file mode 100644 index e99efe062..000000000 --- a/src/pluto/kernel_noklips.c +++ /dev/null @@ -1,124 +0,0 @@ -/* interface to fake kernel interface, used for testing pluto in-vitro. - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org> - * Copyright (C) 2003 Herbert Xu. - * - * 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 <errno.h> -#include <fcntl.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <sys/select.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/queue.h> - -#include <freeswan.h> -#include <pfkeyv2.h> -#include <pfkey.h> - -#include "constants.h" -#include "defs.h" -#include "kernel.h" -#include "kernel_noklips.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ - -void -init_noklips(void) -{ - return; -} - -/* asynchronous messages from our queue */ -static void -noklips_dequeue(void) -{ -} - -/* asynchronous messages directly from PF_KEY socket */ -static void -noklips_event(void) -{ -} - -static void -noklips_register_response(const struct sadb_msg *msg UNUSED) -{ -} - -static void -noklips_register(void) -{ -} - -static bool -noklips_raw_eroute(const ip_address *this_host UNUSED - , const ip_subnet *this_client UNUSED - , const ip_address *that_host UNUSED - , const ip_subnet *that_client UNUSED - , ipsec_spi_t spi UNUSED - , unsigned int satype UNUSED - , unsigned int transport_proto UNUSED - , const struct pfkey_proto_info *proto_info UNUSED - , time_t use_lifetime UNUSED - , unsigned int op UNUSED - , const char *text_said UNUSED) -{ - return TRUE; -} - -static bool -noklips_add_sa(const struct kernel_sa *sa UNUSED - , bool replace UNUSED) -{ - return TRUE; -} - -static bool -noklips_grp_sa(const struct kernel_sa *sa0 UNUSED - , const struct kernel_sa *sa1 UNUSED) -{ - return TRUE; -} - -static bool -noklips_del_sa(const struct kernel_sa *sa UNUSED) -{ - return TRUE; -} - - -const struct kernel_ops noklips_kernel_ops = { - type: KERNEL_TYPE_NONE, - async_fdp: NULL, - - init: init_noklips, - pfkey_register: noklips_register, - pfkey_register_response: noklips_register_response, - process_queue: noklips_dequeue, - process_msg: noklips_event, - raw_eroute: noklips_raw_eroute, - add_sa: noklips_add_sa, - grp_sa: noklips_grp_sa, - del_sa: noklips_del_sa, - get_sa: NULL, - get_spi: NULL, - inbound_eroute: FALSE, - policy_lifetime: FALSE -}; diff --git a/src/pluto/kernel_noklips.h b/src/pluto/kernel_noklips.h deleted file mode 100644 index 3da55d80b..000000000 --- a/src/pluto/kernel_noklips.h +++ /dev/null @@ -1,17 +0,0 @@ -/* declarations of routines that interface with the kernel's pfkey mechanism - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2003 Herbert Xu - * - * 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. - */ - -extern void init_noklips(void); -extern const struct kernel_ops noklips_kernel_ops; diff --git a/src/pluto/kernel_pfkey.c b/src/pluto/kernel_pfkey.c index 99ba4ff30..77fff2f9e 100644 --- a/src/pluto/kernel_pfkey.c +++ b/src/pluto/kernel_pfkey.c @@ -1,7 +1,9 @@ -/* pfkey interface to the kernel's IPsec mechanism - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. +/* + * Copyright (C) 2010 Tobias Brunner + * Hochschule fuer Technik Rapperswil * Copyright (C) 2003 Herbert Xu. + * Copyright (C) 1998-2002 D. Hugh Redelmeier. + * Copyright (C) 1997 Angelos D. Keromytis. * * 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 @@ -14,41 +16,29 @@ * for more details. */ -#ifdef KLIPS - #include <errno.h> -#include <fcntl.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> #include <unistd.h> #include <sys/select.h> -#include <sys/time.h> #include <sys/socket.h> #include <sys/types.h> -#include <sys/queue.h> #include <freeswan.h> #include <pfkeyv2.h> #include <pfkey.h> #include "constants.h" -#include "defs.h" #include "kernel.h" #include "kernel_pfkey.h" #include "log.h" #include "whack.h" /* for RC_LOG_SERIOUS */ -#include "demux.h" -#include "nat_traversal.h" -#include "alg_info.h" #include "kernel_alg.h" static int pfkeyfd = NULL_FD; typedef u_int32_t pfkey_seq_t; -static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */ +static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */ static pid_t pid; @@ -77,106 +67,19 @@ static sparse_names pfkey_type_names = { { 0, sparse_end } }; -#ifdef NEVER /* not needed yet */ -static sparse_names pfkey_ext_names = { - NE(SADB_EXT_RESERVED), - NE(SADB_EXT_SA), - NE(SADB_EXT_LIFETIME_CURRENT), - NE(SADB_EXT_LIFETIME_HARD), - NE(SADB_EXT_LIFETIME_SOFT), - NE(SADB_EXT_ADDRESS_SRC), - NE(SADB_EXT_ADDRESS_DST), - NE(SADB_EXT_ADDRESS_PROXY), - NE(SADB_EXT_KEY_AUTH), - NE(SADB_EXT_KEY_ENCRYPT), - NE(SADB_EXT_IDENTITY_SRC), - NE(SADB_EXT_IDENTITY_DST), - NE(SADB_EXT_SENSITIVITY), - NE(SADB_EXT_PROPOSAL), - NE(SADB_EXT_SUPPORTED_AUTH), - NE(SADB_EXT_SUPPORTED_ENCRYPT), - NE(SADB_EXT_SPIRANGE), - NE(SADB_X_EXT_KMPRIVATE), - NE(SADB_X_EXT_SATYPE2), - NE(SADB_X_EXT_SA2), - NE(SADB_X_EXT_ADDRESS_DST2), - NE(SADB_X_EXT_ADDRESS_SRC_FLOW), - NE(SADB_X_EXT_ADDRESS_DST_FLOW), - NE(SADB_X_EXT_ADDRESS_SRC_MASK), - NE(SADB_X_EXT_ADDRESS_DST_MASK), - NE(SADB_X_EXT_DEBUG), - { 0, sparse_end } -}; -#endif /* NEVER */ - #undef NE -void -init_pfkey(void) -{ - pid = getpid(); - - /* open PF_KEY socket */ - - pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); - - if (pfkeyfd == -1) - exit_log_errno((e, "socket() in init_pfkeyfd()")); - -#ifdef NEVER /* apparently unsupported! */ - if (fcntl(pfkeyfd, F_SETFL, O_NONBLOCK) != 0) - exit_log_errno((e, "fcntl(O_NONBLOCK) in init_pfkeyfd()")); -#endif - if (fcntl(pfkeyfd, F_SETFD, FD_CLOEXEC) != 0) - exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_pfkeyfd()")); - - DBG(DBG_KLIPS, - DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd)); -} - -/* Kinds of PF_KEY message from the kernel: - * - response to a request from us - * + ACK/NAK - * + Register: indicates transforms supported by kernel - * + SPI requested by getspi - * - Acquire, requesting us to deal with trapped clear packet - * - expiration of of one of our SAs - * - messages to other processes - * - * To minimize the effect on the event-driven structure of Pluto, - * responses are dealt with synchronously. We hope that the Kernel - * produces them synchronously. We must "read ahead" in the PF_KEY - * stream, saving Acquire and Expiry messages that are encountered. - * We ignore messages to other processes. - */ - typedef union { unsigned char bytes[PFKEYv2_MAX_MSGSIZE]; struct sadb_msg msg; } pfkey_buf; -/* queue of unprocessed PF_KEY messages input from kernel - * Note that the pfkey_buf may be partly allocated, reflecting - * the variable length nature of the messages. So the link field - * must come first. - */ -typedef struct pfkey_item { - struct pfkey_item *next; - pfkey_buf buf; - } pfkey_item; - -static pfkey_item *pfkey_iq_head = NULL; /* oldest */ -static pfkey_item *pfkey_iq_tail; /* youngest */ - static bool pfkey_input_ready(void) { - fd_set readfds; int ndes; - struct timeval tm; - - tm.tv_sec = 0; /* don't wait at all */ - tm.tv_usec = 0; + fd_set readfds; + struct timeval tm = { .tv_sec = 0 }; /* don't wait, polling */ FD_ZERO(&readfds); /* we only care about pfkeyfd */ FD_SET(pfkeyfd, &readfds); @@ -190,16 +93,16 @@ pfkey_input_ready(void) log_errno((e, "select() failed in pfkey_get()")); return FALSE; } - - if (ndes == 0) + else if (ndes == 0) + { return FALSE; /* nothing to read */ - + } passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds)); return TRUE; } /* get a PF_KEY message from kernel. - * Returns TRUE is message found, FALSE if no message pending, + * Returns TRUE if message found, FALSE if no message pending, * and aborts or keeps trying when an error is encountered. * The only validation of the message is that the message length * received matches that in the message header, and that the message @@ -216,48 +119,48 @@ pfkey_get(pfkey_buf *buf) ssize_t len; if (!pfkey_input_ready()) + { return FALSE; + } len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes)); if (len < 0) { if (errno == EAGAIN) + { return FALSE; - + } log_errno((e, "read() failed in pfkey_get()")); return FALSE; } - else if ((size_t) len < sizeof(buf->msg)) + else if ((size_t)len < sizeof(buf->msg)) { - plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring message" - , (int) len); + plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring", + (int)len); } - else if ((size_t) len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN) + else if ((size_t)len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN) { - plog("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %u; ignoring message" - , (int) len - , (unsigned) buf->msg.sadb_msg_len - , (unsigned) IPSEC_PFKEYv2_ALIGN); + plog("pfkey_get read PF_KEY message with length %d that doesn't" + " equal sadb_msg_len %u * %u; ignoring message", (int)len, + (unsigned)buf->msg.sadb_msg_len, (unsigned)IPSEC_PFKEYv2_ALIGN); } - else if (!(buf->msg.sadb_msg_pid == (unsigned)pid - || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE) - || (buf->msg.sadb_msg_type == SADB_REGISTER) - || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING))) + else if (buf->msg.sadb_msg_pid != (unsigned)pid) { /* not for us: ignore */ - DBG(DBG_KLIPS, - DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process %u" - , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type) - , buf->msg.sadb_msg_seq - , buf->msg.sadb_msg_pid)); + DBG(DBG_KERNEL, + DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process" + " %u", sparse_val_show(pfkey_type_names, + buf->msg.sadb_msg_type), + buf->msg.sadb_msg_seq, buf->msg.sadb_msg_pid)); } else { - DBG(DBG_KLIPS, - DBG_log("pfkey_get: %s message %u" - , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type) - , buf->msg.sadb_msg_seq)); + DBG(DBG_KERNEL, + DBG_log("pfkey_get: %s message %u", + sparse_val_show(pfkey_type_names, + buf->msg.sadb_msg_type), + buf->msg.sadb_msg_seq)); return TRUE; } } @@ -269,285 +172,49 @@ pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq) { while (pfkey_get(buf)) { - if (buf->msg.sadb_msg_pid == (unsigned)pid - && buf->msg.sadb_msg_seq == seq) + if (buf->msg.sadb_msg_seq == seq) { return TRUE; } - else - { - /* Not for us: queue it. */ - size_t bl = buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN; - pfkey_item *it = malloc(offsetof(pfkey_item, buf) + bl); - - memcpy(&it->buf, buf, bl); - - it->next = NULL; - if (pfkey_iq_head == NULL) - { - pfkey_iq_head = it; - } - else - { - pfkey_iq_tail->next = it; - } - pfkey_iq_tail = it; - } } return FALSE; } -/* Process a SADB_REGISTER message from the kernel. - * This will be a response to one of ours, but it may be asynchronous - * (if kernel modules are loaded and unloaded). - * Some sanity checking has already been performed. - */ -static void -klips_pfkey_register_response(const struct sadb_msg *msg) -{ - /* Find out what the kernel can support. - * In fact, the only question at the moment - * is whether it can support IPcomp. - * So we ignore the rest. - * ??? we really should pay attention to what transforms are supported. - */ - switch (msg->sadb_msg_satype) - { - case SADB_SATYPE_AH: - break; - case SADB_SATYPE_ESP: -#ifndef NO_KERNEL_ALG - kernel_alg_register_pfkey(msg, sizeof (pfkey_buf)); -#endif - break; - case SADB_X_SATYPE_COMP: - /* ??? There ought to be an extension to list the - * supported algorithms, but RFC 2367 doesn't - * list one for IPcomp. KLIPS uses SADB_X_CALG_DEFLATE. - * Since we only implement deflate, we'll assume this. - */ - can_do_IPcomp = TRUE; - break; - case SADB_X_SATYPE_IPIP: - break; - default: - break; - } -} - -/* Processs a SADB_ACQUIRE message from KLIPS. - * Try to build an opportunistic connection! - * See RFC 2367 "PF_KEY Key Management API, Version 2" 3.1.6 - * <base, address(SD), (address(P)), (identity(SD),) (sensitivity,) proposal> - * - extensions for source and data IP addresses - * - optional extensions for identity [not useful for us?] - * - optional extension for sensitivity [not useful for us?] - * - expension for proposal [not useful for us?] - * - * ??? We must use the sequence number in creating an SA. - * We actually need to create up to 4 SAs each way. Which one? - * I guess it depends on the protocol present in the sadb_msg_satype. - * For now, we'll ignore this requirement. - * - * ??? We need some mechanism to make sure that multiple ACQUIRE messages - * don't cause a whole bunch of redundant negotiations. - */ -static void -process_pfkey_acquire(pfkey_buf *buf, struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC]; - struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST]; - int src_proto = srcx->sadb_address_proto; - int dst_proto = dstx->sadb_address_proto; - ip_address *src = (ip_address*)&srcx[1]; - ip_address *dst = (ip_address*)&dstx[1]; - ip_subnet ours, his; - err_t ugh = NULL; - - /* assumption: we're only catching our own outgoing packets - * so source is our end and destination is the other end. - * Verifying this is not actually convenient. - * - * This stylized control structure yields a complaint or - * desired results. For compactness, a pointer value is - * treated as a boolean. Logically, the structure is: - * keep going as long as things are OK. - */ - if (buf->msg.sadb_msg_pid == 0 /* we only wish to hear from kernel */ - && !(ugh = src_proto == dst_proto? NULL : "src and dst protocols differ") - && !(ugh = addrtypeof(src) == addrtypeof(dst)? NULL : "conflicting address types") - && !(ugh = addrtosubnet(src, &ours)) - && !(ugh = addrtosubnet(dst, &his))) - record_and_initiate_opportunistic(&ours, &his, src_proto, "%acquire"); - - if (ugh != NULL) - plog("SADB_ACQUIRE message from KLIPS malformed: %s", ugh); - -} - -/* Handle PF_KEY messages from the kernel that are not dealt with - * synchronously. In other words, all but responses to PF_KEY messages - * that we sent. - */ -static void -pfkey_async(pfkey_buf *buf) -{ - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - - if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT)) - { - plog("pfkey_async:" - " unparseable PF_KEY message:" - " %s len=%d, errno=%d, seq=%d, pid=%d; message ignored" - , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type) - , buf->msg.sadb_msg_len - , buf->msg.sadb_msg_errno - , buf->msg.sadb_msg_seq - , buf->msg.sadb_msg_pid); - } - else - { - DBG(DBG_CONTROL | DBG_KLIPS, DBG_log("pfkey_async:" - " %s len=%u, errno=%u, satype=%u, seq=%u, pid=%u" - , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type) - , buf->msg.sadb_msg_len - , buf->msg.sadb_msg_errno - , buf->msg.sadb_msg_satype - , buf->msg.sadb_msg_seq - , buf->msg.sadb_msg_pid)); - - switch (buf->msg.sadb_msg_type) - { - case SADB_REGISTER: - kernel_ops->pfkey_register_response(&buf->msg); - break; - case SADB_ACQUIRE: - /* to simulate loss of ACQUIRE, delete this call */ - process_pfkey_acquire(buf, extensions); - break; - case SADB_X_NAT_T_NEW_MAPPING: - process_pfkey_nat_t_new_mapping(&(buf->msg), extensions); - break; - default: - /* ignored */ - break; - } - } -} - -/* asynchronous messages from our queue */ -static void -pfkey_dequeue(void) -{ - while (pfkey_iq_head != NULL) - { - pfkey_item *it = pfkey_iq_head; - - pfkey_async(&it->buf); - pfkey_iq_head = it->next; - free(it); - } - - /* Handle any orphaned holds, but only if no pfkey input is pending. - * For each, we initiate Opportunistic. - * note: we don't need to advance the pointer because - * record_and_initiate_opportunistic will remove the current - * record each time we call it. - */ - while (orphaned_holds != NULL && !pfkey_input_ready()) - record_and_initiate_opportunistic(&orphaned_holds->ours - , &orphaned_holds->his - , orphaned_holds->transport_proto - , "%hold found-pfkey"); - -} - -/* asynchronous messages directly from PF_KEY socket */ -static void -pfkey_event(void) -{ - pfkey_buf buf; - - if (pfkey_get(&buf)) - pfkey_async(&buf); -} - static bool -pfkey_build(int error -, const char *description -, const char *text_said -, struct sadb_ext *extensions[SADB_EXT_MAX + 1]) +pfkey_build(int error, const char *description, const char *text_said, + struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { - if (error == 0) - { - return TRUE; - } - else + if (error != 0) { - loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d" - , description, text_said, error); + loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d", description, + text_said, error); pfkey_extensions_free(extensions); return FALSE; } + return TRUE; } /* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */ static bool -pfkey_msg_start(u_int8_t msg_type -, u_int8_t satype -, const char *description -, const char *text_said -, struct sadb_ext *extensions[SADB_EXT_MAX + 1]) +pfkey_msg_start(u_int8_t msg_type, u_int8_t satype, const char *description, + const char *text_said, + struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { pfkey_extensions_init(extensions); - return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type - , satype, 0, ++pfkey_seq, pid) - , description, text_said, extensions); -} - -/* pfkey_build + pfkey_address_build */ -static bool -pfkeyext_address(u_int16_t exttype -, const ip_address *address -, const char *description -, const char *text_said -, struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - /* the following variable is only needed to silence - * a warning caused by the fact that the argument - * to sockaddrof is NOT pointer to const! - */ - ip_address t = *address; - - return pfkey_build(pfkey_address_build(extensions + exttype - , exttype, 0, 0, sockaddrof(&t)) - , description, text_said, extensions); -} - -/* pfkey_build + pfkey_x_protocol_build */ -static bool -pfkeyext_protocol(int transport_proto -, const char *description -, const char *text_said -, struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - return (transport_proto == 0)? TRUE - : pfkey_build( - pfkey_x_protocol_build(extensions + SADB_X_EXT_PROTOCOL, transport_proto) - , description, text_said, extensions); + return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type, satype, 0, + ++pfkey_seq, pid), + description, text_said, extensions); } - /* Finish (building, sending, accepting response for) PF_KEY message. * If response isn't NULL, the response from the kernel will be * placed there (and its errno field will not be examined). * Returns TRUE iff all appears well. */ static bool -finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1] -, const char *description -, const char *text_said -, pfkey_buf *response) +finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1], + const char *description, const char *text_said, + pfkey_buf *response) { struct sadb_msg *pfkey_msg; bool success = TRUE; @@ -557,368 +224,157 @@ finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1] if (error != 0) { - loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d" - , description, text_said, error); + loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d", + description, text_said, error); success = FALSE; } else { size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN; - DBG(DBG_KLIPS, - DBG_log("finish_pfkey_msg: %s message %u for %s %s" - , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) - , pfkey_msg->sadb_msg_seq - , description, text_said); + DBG(DBG_KERNEL, + DBG_log("finish_pfkey_msg: %s message %u for %s %s", + sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type), + pfkey_msg->sadb_msg_seq, description, text_said); DBG_dump(NULL, (void *) pfkey_msg, len)); - if (!no_klips) - { - ssize_t r = write(pfkeyfd, pfkey_msg, len); + ssize_t r = write(pfkeyfd, pfkey_msg, len); - if (r != (ssize_t)len) + if (r != (ssize_t)len) + { + if (r < 0) { - if (r < 0) - { - log_errno((e - , "pfkey write() of %s message %u" - " for %s %s failed" - , sparse_val_show(pfkey_type_names - , pfkey_msg->sadb_msg_type) - , pfkey_msg->sadb_msg_seq - , description, text_said)); - } - else - { - loglog(RC_LOG_SERIOUS - , "ERROR: pfkey write() of %s message %u" - " for %s %s truncated: %ld instead of %ld" - , sparse_val_show(pfkey_type_names - , pfkey_msg->sadb_msg_type) - , pfkey_msg->sadb_msg_seq - , description, text_said - , (long)r, (long)len); - } - success = FALSE; + log_errno((e, "pfkey write() of %s message %u for %s %s" + " failed", sparse_val_show(pfkey_type_names, + pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq, + description, text_said)); + } + else + { + loglog(RC_LOG_SERIOUS, "ERROR: pfkey write() of %s message" + " %u for %s %s truncated: %ld instead of %ld", + sparse_val_show(pfkey_type_names, + pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq, + description, text_said, (long)r, (long)len); + } + success = FALSE; - /* if we were compiled with debugging, but we haven't already - * dumped the KLIPS command, do so. - */ + /* if we were compiled with debugging, but we haven't already + * dumped the command, do so. + */ #ifdef DEBUG - if ((cur_debugging & DBG_KLIPS) == 0) - DBG_dump(NULL, (void *) pfkey_msg, len); + if ((cur_debugging & DBG_KERNEL) == 0) + DBG_dump(NULL, (void *) pfkey_msg, len); #endif + } + else + { + /* Check response from kernel. + * It ought to be an echo, perhaps with additional info. + * If the caller wants it, response will point to space. + */ + pfkey_buf b; + pfkey_buf *bp = response != NULL? response : &b; + + if (!pfkey_get_response(bp, + ((struct sadb_msg *)extensions[0])->sadb_msg_seq)) + { + loglog(RC_LOG_SERIOUS, "ERROR: no response to our PF_KEY %s" + " message for %s %s", sparse_val_show(pfkey_type_names, + pfkey_msg->sadb_msg_type), description, text_said); + success = FALSE; } - else + else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type) { - /* Check response from KLIPS. - * It ought to be an echo, perhaps with additional info. - * If the caller wants it, response will point to space. - */ - pfkey_buf b; - pfkey_buf *bp = response != NULL? response : &b; - - if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq)) - { - loglog(RC_LOG_SERIOUS - , "ERROR: no response to our PF_KEY %s message for %s %s" - , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) - , description, text_said); - success = FALSE; - } - else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type) - { - loglog(RC_LOG_SERIOUS - , "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)" - , sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type) - , description, text_said - , sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type)); - success = FALSE; - } - else if (response == NULL && bp->msg.sadb_msg_errno != 0) - { - /* KLIPS is signalling a problem */ - loglog(RC_LOG_SERIOUS - , "ERROR: PF_KEY %s response for %s %s included errno %u: %s" - , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) - , description, text_said - , (unsigned) bp->msg.sadb_msg_errno - , strerror(bp->msg.sadb_msg_errno)); - success = FALSE; - } + loglog(RC_LOG_SERIOUS, "ERROR: response to our PF_KEY %s" + " message for %s %s was of wrong type (%s)", + sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type), + description, text_said, sparse_val_show(pfkey_type_names, + bp->msg.sadb_msg_type)); + success = FALSE; + } + else if (response == NULL && bp->msg.sadb_msg_errno != 0) + { + /* Kernel is signalling a problem */ + loglog(RC_LOG_SERIOUS, "ERROR: PF_KEY %s response for %s %s" + " included errno %u: %s", + sparse_val_show(pfkey_type_names, + pfkey_msg->sadb_msg_type), description, text_said, + (unsigned) bp->msg.sadb_msg_errno, + strerror(bp->msg.sadb_msg_errno)); + success = FALSE; } } } - - /* all paths must exit this way to free resources */ pfkey_extensions_free(extensions); pfkey_msg_free(&pfkey_msg); return success; } -/* register SA types that can be negotiated */ -void -pfkey_register_proto(unsigned satype, const char *satypename) +/* Process a SADB_REGISTER message from the kernel. + * This will be a response to one of ours, but it may be asynchronous + * (if kernel modules are loaded and unloaded). + * Some sanity checking has already been performed. + */ +static void +pfkey_register_response(const struct sadb_msg *msg) { - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - pfkey_buf pfb; - - if (!(pfkey_msg_start(SADB_REGISTER - , satype - , satypename, NULL, extensions) - && finish_pfkey_msg(extensions, satypename, "", &pfb))) - { - /* ??? should this be loglog */ - plog("no KLIPS support for %s", satypename); - } - else + /* Find out what the kernel can support. + */ + switch (msg->sadb_msg_satype) { - kernel_ops->pfkey_register_response(&pfb.msg); - DBG(DBG_KLIPS, - DBG_log("%s registered with kernel.", satypename)); + case SADB_SATYPE_ESP: +#ifndef NO_KERNEL_ALG + kernel_alg_register_pfkey(msg, sizeof (pfkey_buf)); +#endif + break; + case SADB_X_SATYPE_IPCOMP: + /* ??? There ought to be an extension to list the + * supported algorithms, but RFC 2367 doesn't + * list one for IPcomp. + */ + can_do_IPcomp = TRUE; + break; + default: + break; } } +/** register SA types that can be negotiated */ static void -klips_pfkey_register(void) -{ - pfkey_register_proto(SADB_SATYPE_AH, "AH"); - pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); - can_do_IPcomp = FALSE; /* until we get a response from KLIPS */ - pfkey_register_proto(SADB_X_SATYPE_COMP, "IPCOMP"); - pfkey_register_proto(SADB_X_SATYPE_IPIP, "IPIP"); -} - -static bool -pfkey_raw_eroute(const ip_address *this_host - , const ip_subnet *this_client - , const ip_address *that_host - , const ip_subnet *that_client - , ipsec_spi_t spi - , unsigned int satype - , unsigned int transport_proto - , const struct pfkey_proto_info *proto_info UNUSED - , time_t use_lifetime UNUSED - , unsigned int op - , const char *text_said) +pfkey_register_proto(unsigned satype, const char *satypename) { struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - ip_address - sflow_ska, - dflow_ska, - smask_ska, - dmask_ska; - int sport = ntohs(portof(&this_client->addr)); - int dport = ntohs(portof(&that_client->addr)); - - networkof(this_client, &sflow_ska); - maskof(this_client, &smask_ska); - setportof(sport ? ~0:0, &smask_ska); - - networkof(that_client, &dflow_ska); - maskof(that_client, &dmask_ska); - setportof(dport ? ~0:0, &dmask_ska); - - if (!pfkey_msg_start(op & ERO_MASK, satype - , "pfkey_msg_hdr flow", text_said, extensions)) - { - return FALSE; - } - - if (op != ERO_DELETE) - { - if (!(pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] - , SADB_EXT_SA - , spi /* in network order */ - , 0, 0, 0, 0, op >> ERO_FLAG_SHIFT) - , "pfkey_sa add flow", text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_SRC, this_host - , "pfkey_addr_s add flow", text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_DST, that_host - , "pfkey_addr_d add flow", text_said - , extensions))) - { - return FALSE; - } - } - - if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_FLOW, &sflow_ska - , "pfkey_addr_sflow", text_said, extensions)) - { - return FALSE; - } - - if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_FLOW, &dflow_ska - , "pfkey_addr_dflow", text_said, extensions)) - { - return FALSE; - } - - if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_MASK, &smask_ska - , "pfkey_addr_smask", text_said, extensions)) - { - return FALSE; - } + pfkey_buf pfb; - if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_MASK, &dmask_ska - , "pfkey_addr_dmask", text_said, extensions)) + if (!(pfkey_msg_start(SADB_REGISTER, satype, satypename, NULL, extensions) + && finish_pfkey_msg(extensions, satypename, "", &pfb))) { - return FALSE; + /* ??? should this be loglog */ + plog("no kernel support for %s", satypename); } - - if (!pfkeyext_protocol(transport_proto - , "pfkey_x_protocol", text_said, extensions)) + else { - return FALSE; + pfkey_register_response(&pfb.msg); + DBG(DBG_KERNEL, + DBG_log("%s registered with kernel.", satypename)); } - - return finish_pfkey_msg(extensions, "flow", text_said, NULL); -} - -static bool -pfkey_add_sa(const struct kernel_sa *sa, bool replace) -{ - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - - return pfkey_msg_start(replace ? SADB_UPDATE : SADB_ADD, sa->satype - , "pfkey_msg_hdr Add SA", sa->text_said, extensions) - - && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] - , SADB_EXT_SA - , sa->spi /* in network order */ - , sa->replay_window, SADB_SASTATE_MATURE - , sa->authalg, sa->encalg ? sa->encalg: sa->compalg, 0) - , "pfkey_sa Add SA", sa->text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src - , "pfkey_addr_s Add SA", sa->text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst - , "pfkey_addr_d Add SA", sa->text_said, extensions) - - && (sa->authkeylen == 0 - || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH] - , SADB_EXT_KEY_AUTH, sa->authkeylen * BITS_PER_BYTE - , sa->authkey) - , "pfkey_key_a Add SA", sa->text_said, extensions)) - - && (sa->enckeylen == 0 - || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT] - , SADB_EXT_KEY_ENCRYPT, sa->enckeylen * BITS_PER_BYTE - , sa->enckey) - , "pfkey_key_e Add SA", sa->text_said, extensions)) - - && (sa->natt_type == 0 - || pfkey_build(pfkey_x_nat_t_type_build( - &extensions[SADB_X_EXT_NAT_T_TYPE], sa->natt_type), - "pfkey_nat_t_type Add ESP SA", sa->text_said, extensions)) - && (sa->natt_sport == 0 - || pfkey_build(pfkey_x_nat_t_port_build( - &extensions[SADB_X_EXT_NAT_T_SPORT], SADB_X_EXT_NAT_T_SPORT, - sa->natt_sport), "pfkey_nat_t_sport Add ESP SA", sa->text_said, - extensions)) - && (sa->natt_dport == 0 - || pfkey_build(pfkey_x_nat_t_port_build( - &extensions[SADB_X_EXT_NAT_T_DPORT], SADB_X_EXT_NAT_T_DPORT, - sa->natt_dport), "pfkey_nat_t_dport Add ESP SA", sa->text_said, - extensions)) - && (sa->natt_type == 0 || isanyaddr(sa->natt_oa) - || pfkeyext_address(SADB_X_EXT_NAT_T_OA, sa->natt_oa - , "pfkey_nat_t_oa Add ESP SA", sa->text_said, extensions)) - - && finish_pfkey_msg(extensions, "Add SA", sa->text_said, NULL); - -} - -static bool -pfkey_grp_sa(const struct kernel_sa *sa0, const struct kernel_sa *sa1) -{ - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - - return pfkey_msg_start(SADB_X_GRPSA, sa1->satype - , "pfkey_msg_hdr group", sa1->text_said, extensions) - - && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] - , SADB_EXT_SA - , sa1->spi /* in network order */ - , 0, 0, 0, 0, 0) - , "pfkey_sa group", sa1->text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa1->dst - , "pfkey_addr_d group", sa1->text_said, extensions) - - && pfkey_build(pfkey_x_satype_build(&extensions[SADB_X_EXT_SATYPE2] - , sa0->satype) - , "pfkey_satype group", sa0->text_said, extensions) - - && pfkey_build(pfkey_sa_build(&extensions[SADB_X_EXT_SA2] - , SADB_X_EXT_SA2 - , sa0->spi /* in network order */ - , 0, 0, 0, 0, 0) - , "pfkey_sa2 group", sa0->text_said, extensions) - - && pfkeyext_address(SADB_X_EXT_ADDRESS_DST2, sa0->dst - , "pfkey_addr_d2 group", sa0->text_said, extensions) - - && finish_pfkey_msg(extensions, "group", sa1->text_said, NULL); -} - -static bool -pfkey_del_sa(const struct kernel_sa *sa) -{ - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - - return pfkey_msg_start(SADB_DELETE, proto2satype(sa->proto) - , "pfkey_msg_hdr delete SA", sa->text_said, extensions) - - && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] - , SADB_EXT_SA - , sa->spi /* in host order */ - , 0, SADB_SASTATE_MATURE, 0, 0, 0) - , "pfkey_sa delete SA", sa->text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src - , "pfkey_addr_s delete SA", sa->text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst - , "pfkey_addr_d delete SA", sa->text_said, extensions) - - && finish_pfkey_msg(extensions, "Delete SA", sa->text_said, NULL); } void -pfkey_close(void) +pfkey_register(void) { - while (pfkey_iq_head != NULL) - { - pfkey_item *it = pfkey_iq_head; + pid = getpid(); - pfkey_iq_head = it->next; - free(it); + pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); + if (pfkeyfd == -1) + { + exit_log_errno((e, "socket() in init_pfkeyfd()")); } + pfkey_register_proto(SADB_SATYPE_AH, "AH"); + pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); + pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP"); + close(pfkeyfd); - pfkeyfd = NULL_FD; } - -const struct kernel_ops klips_kernel_ops = { - type: KERNEL_TYPE_KLIPS, - async_fdp: &pfkeyfd, - - pfkey_register: klips_pfkey_register, - pfkey_register_response: klips_pfkey_register_response, - process_queue: pfkey_dequeue, - process_msg: pfkey_event, - raw_eroute: pfkey_raw_eroute, - add_sa: pfkey_add_sa, - grp_sa: pfkey_grp_sa, - del_sa: pfkey_del_sa, - get_sa: NULL, - get_spi: NULL, - inbound_eroute: FALSE, - policy_lifetime: FALSE, - init: NULL -}; -#endif /* KLIPS */ diff --git a/src/pluto/kernel_pfkey.h b/src/pluto/kernel_pfkey.h index ad20a5888..b50ad6c37 100644 --- a/src/pluto/kernel_pfkey.h +++ b/src/pluto/kernel_pfkey.h @@ -1,6 +1,6 @@ -/* declarations of routines that interface with the kernel's pfkey mechanism - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2003 Herbert Xu +/* + * Copyright (C) 2010 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 @@ -13,9 +13,8 @@ * for more details. */ -#ifdef KLIPS -extern void init_pfkey(void); -extern void pfkey_register_proto(unsigned satype, const char *satypename); -extern void pfkey_close(void); -extern const struct kernel_ops klips_kernel_ops; -#endif +/** + * Register our capabilities via PF_KEY, also learn the kernel's capabilities, + * i.e. the supported algorithms. + */ +void pfkey_register(); diff --git a/src/pluto/keys.c b/src/pluto/keys.c index 6db757ba7..a79c2c0d2 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -37,6 +37,8 @@ #include <library.h> #include <asn1/asn1.h> #include <credentials/certificates/pgp_certificate.h> +#include <credentials/sets/mem_cred.h> +#include <credentials/sets/callback_cred.h> #include "constants.h" #include "defs.h" @@ -539,6 +541,128 @@ end: return ugh; } +/* struct used to prompt for a secret passphrase + * from a console with file descriptor fd + */ +typedef struct { + char secret[PROMPT_PASS_LEN+1]; + bool prompt; + int fd; + int try; +} prompt_pass_t; + +/** + * Passphrase callback to read from whack fd + */ +static shared_key_t* whack_pass_cb(prompt_pass_t *pass, shared_key_type_t type, + identification_t *me, identification_t *other, + id_match_t *match_me, id_match_t *match_other) +{ + int n; + + if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS) + { + return NULL; + } + + if (pass->try > MAX_PROMPT_PASS_TRIALS) + { + whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials"); + return NULL; + } + if (pass->try == 1) + { + whack_log(RC_ENTERSECRET, "need passphrase for 'private key'"); + } + else + { + whack_log(RC_ENTERSECRET, "invalid passphrase, please try again"); + } + pass->try++; + + n = read(pass->fd, pass->secret, PROMPT_PASS_LEN); + if (n == -1) + { + whack_log(RC_LOG_SERIOUS, "read(whackfd) failed"); + return NULL; + } + pass->secret[n-1] = '\0'; + + if (strlen(pass->secret) == 0) + { + whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted"); + return NULL; + } + if (match_me) + { + *match_me = ID_MATCH_PERFECT; + } + if (match_other) + { + *match_other = ID_MATCH_NONE; + } + return shared_key_create(SHARED_PRIVATE_KEY_PASS, + chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); +} + +/** + * Loads a PKCS#1 or PGP private key file + */ +static private_key_t* load_private_key(char* filename, prompt_pass_t *pass, + key_type_t type) +{ + private_key_t *key = NULL; + char *path; + + path = concatenate_paths(PRIVATE_KEY_PATH, filename); + if (pass && pass->prompt && pass->fd != NULL_FD) + { /* use passphrase callback */ + callback_cred_t *cb; + + cb = callback_cred_create_shared((void*)whack_pass_cb, pass); + lib->credmgr->add_local_set(lib->credmgr, &cb->set); + + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_FROM_FILE, path, BUILD_END); + lib->credmgr->remove_local_set(lib->credmgr, &cb->set); + cb->destroy(cb); + if (key) + { + whack_log(RC_SUCCESS, "valid passphrase"); + } + } + else if (pass) + { /* use a given passphrase */ + mem_cred_t *mem; + shared_key_t *shared; + + mem = mem_cred_create(); + lib->credmgr->add_local_set(lib->credmgr, &mem->set); + shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, + chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); + mem->add_shared(mem, shared, NULL); + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_FROM_FILE, path, BUILD_END); + lib->credmgr->remove_local_set(lib->credmgr, &mem->set); + mem->destroy(mem); + } + else + { /* no passphrase */ + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_FROM_FILE, path, BUILD_END); + + } + if (key) + { + plog(" loaded private key from '%s'", filename); + } + else + { + plog(" syntax error in private key file"); + } + return key; +} + /** * process a key file protected with optional passphrase which can either be * read from ipsec.secrets or prompted for by using whack @@ -552,6 +676,7 @@ static err_t process_keyfile(private_key_t **key, key_type_t type, int whackfd) memset(pass.secret,'\0', sizeof(pass.secret)); pass.prompt = FALSE; pass.fd = whackfd; + pass.try = 1; /* we expect the filename of a PKCS#1 private key file */ @@ -1324,7 +1449,7 @@ void list_public_keys(bool utc) whack_log(RC_COMMENT, " identity: '%Y'", key->id); whack_log(RC_COMMENT, " pubkey: %N %4d bits, until %T %s", key_type_names, public->get_type(public), - public->get_keysize(public) * BITS_PER_BYTE, + public->get_keysize(public), &key->until_time, utc, check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE)); if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) diff --git a/src/pluto/log.c b/src/pluto/log.c index 444ac2220..6e70898a5 100644 --- a/src/pluto/log.c +++ b/src/pluto/log.c @@ -862,9 +862,6 @@ void show_status(bool all, const char *name) } show_connections_status(all, name); show_states_status(all, name); -#ifdef KLIPS - show_shunt_status(); -#endif } /* ip_str: a simple to use variant of addrtot. diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c index 0d0cd899c..a2acce23a 100644 --- a/src/pluto/modecfg.c +++ b/src/pluto/modecfg.c @@ -419,7 +419,7 @@ static stf_status modecfg_build_msg(struct state *st, pb_stream *rbody, close_output_pbs(&attrval); } enumerator->destroy(enumerator); - close_message(&strattr); + close_output_pbs(&strattr); modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); close_message(rbody); diff --git a/src/pluto/nat_traversal.c b/src/pluto/nat_traversal.c index feedf2aad..5e9353b72 100644 --- a/src/pluto/nat_traversal.c +++ b/src/pluto/nat_traversal.c @@ -1,6 +1,9 @@ -/* FreeS/WAN NAT-Traversal - * Copyright (C) 2002-2005 Mathieu Lafon - Arkoon Network Security - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil +/* + * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * Copyright (C) 2002-2005 Mathieu Lafon + * Arkoon Network Security * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -24,10 +27,6 @@ #include <signal.h> /* used only if MSG_NOSIGNAL not defined */ #include <sys/queue.h> -#include <freeswan.h> -#include <pfkeyv2.h> -#include <pfkey.h> - #include <library.h> #include <crypto/hashers/hasher.h> @@ -796,80 +795,51 @@ void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st) } } -struct _new_klips_mapp_nfo { - struct sadb_sa *sa; - ip_address src, dst; - u_int16_t sport, dport; +struct _new_kernel_mapp_nfo { + u_int32_t reqid; + u_int32_t spi; + ip_address *addr; }; -static void nat_t_new_klips_mapp (struct state *st, void *data) +static void nat_t_new_kernel_mapp (struct state *st, void *data) { connection_t *c = st->st_connection; - struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data; + struct _new_kernel_mapp_nfo *nfo = (struct _new_kernel_mapp_nfo *)data; if (c != NULL && st->st_esp.present - && sameaddr(&c->spd.that.host_addr, &(nfo->src)) - && st->st_esp.our_spi == nfo->sa->sadb_sa_spi) - { - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - &(nfo->dst), nfo->dport); - } -} - -void process_pfkey_nat_t_new_mapping( - struct sadb_msg *msg __attribute__ ((unused)), - struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - struct _new_klips_mapp_nfo nfo; - struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC]; - struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST]; - struct sockaddr *srca, *dsta; - err_t ugh = NULL; - - nfo.sa = (void *) extensions[SADB_EXT_SA]; - - if (!nfo.sa || !srcx || !dstx) + && nfo->spi == st->st_esp.our_spi + && nfo->reqid == c->spd.reqid) { - plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: " - "got NULL params"); - return; - } - - srca = ((struct sockaddr *)(void *)&srcx[1]); - dsta = ((struct sockaddr *)(void *)&dstx[1]); + u_int16_t port = ntohs(portof(nfo->addr)); - if (srca->sa_family != AF_INET || dsta->sa_family != AF_INET) - { - ugh = "only AF_INET supported"; - } - else - { - char text_said[SATOT_BUF]; - char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF]; - ip_said said; - - initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr, - sizeof(((const struct sockaddr_in *)srca)->sin_addr), - srca->sa_family, &(nfo.src)); - nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port); - initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr, - sizeof(((const struct sockaddr_in *)dsta)->sin_addr), - dsta->sa_family, &(nfo.dst)); - nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port); + DBG(DBG_NATT, { + char text_said[SATOT_BUF]; + char olda[ADDRTOT_BUF]; + char newa[ADDRTOT_BUF]; + ip_said said; - DBG(DBG_NATT, - initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said); + initsaid(&c->spd.that.host_addr, nfo->spi, SA_ESP, &said); satot(&said, 0, text_said, SATOT_BUF); - addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF); - addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF); - DBG_log("new klips mapping %s %s:%d %s:%d", - text_said, _srca, nfo.sport, _dsta, nfo.dport); - ) + addrtot(&c->spd.that.host_addr, 0, olda, ADDRTOT_BUF); + addrtot(nfo->addr, 0, newa, ADDRTOT_BUF); + + DBG_log("new kernel mapping %s %s:%d %s:%d", + text_said, olda, c->spd.that.host_port, newa, port); + }) - for_each_state((void *)nat_t_new_klips_mapp, &nfo); + nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, + nfo->addr, port); } +} - if (ugh != NULL) - plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh); +void process_nat_t_new_mapping(u_int32_t reqid, u_int32_t spi, + ip_address *new_end) +{ + struct _new_kernel_mapp_nfo nfo = { + .reqid = reqid, + .spi = spi, + .addr = new_end, + }; + for_each_state((void *)nat_t_new_kernel_mapp, &nfo); } diff --git a/src/pluto/nat_traversal.h b/src/pluto/nat_traversal.h index 98b0a2bc0..80bdaf787 100644 --- a/src/pluto/nat_traversal.h +++ b/src/pluto/nat_traversal.h @@ -1,5 +1,8 @@ -/* FreeS/WAN NAT-Traversal - * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security +/* + * Copyright (C) 2010 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * Copyright (C) 2002-2003 Mathieu Lafon + * Arkoon Network Security * * 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 @@ -115,11 +118,8 @@ void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st); /** * New NAT mapping */ -#ifdef __PFKEY_V2_H -void process_pfkey_nat_t_new_mapping( - struct sadb_msg *, - struct sadb_ext *[SADB_EXT_MAX + 1]); -#endif +void process_nat_t_new_mapping(u_int32_t reqid, u_int32_t spi, + ip_address *new_end); /** * IKE port floating diff --git a/src/pluto/pkcs7.c b/src/pluto/pkcs7.c index c0fd041a7..10b2a4d5a 100644 --- a/src/pluto/pkcs7.c +++ b/src/pluto/pkcs7.c @@ -407,7 +407,7 @@ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, } break; case PKCS7_ENCRYPTED_KEY: - if (!key->decrypt(key, object, &symmetric_key)) + if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key)) { DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa"); goto end; @@ -473,7 +473,7 @@ end: DBG1(DBG_LIB, "symmetric key length %d is wrong", symmetric_key.len); goto failed; } - if (iv.len != crypter->get_block_size(crypter)) + if (iv.len != crypter->get_iv_size(crypter)) { DBG1(DBG_LIB, "IV length %d is wrong", iv.len); goto failed; @@ -668,7 +668,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg rng->destroy(rng); rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->allocate_bytes(rng, crypter->get_block_size(crypter), &iv); + rng->allocate_bytes(rng, crypter->get_iv_size(crypter), &iv); DBG4(DBG_LIB, "initialization vector: %B", &iv); rng->destroy(rng); } @@ -710,7 +710,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg chunk_free(&out); return chunk_empty; } - key->encrypt(key, symmetricKey, &protectedKey); + key->encrypt(key, ENCRYPT_RSA_PKCS1, symmetricKey, &protectedKey); key->destroy(key); } diff --git a/src/pluto/plugins/xauth/Makefile.in b/src/pluto/plugins/xauth/Makefile.in index 13749e5af..b2ffb11db 100644 --- a/src/pluto/plugins/xauth/Makefile.in +++ b/src/pluto/plugins/xauth/Makefile.in @@ -44,6 +44,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.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) @@ -163,6 +164,8 @@ 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@ @@ -194,14 +197,17 @@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ +c_plugins = @c_plugins@ datadir = @datadir@ datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ default_pkcs11 = @default_pkcs11@ 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@ @@ -216,24 +222,31 @@ ipsecgid = @ipsecgid@ ipsecgroup = @ipsecgroup@ ipsecuid = @ipsecuid@ ipsecuser = @ipsecuser@ +libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ -libhydra_plugins = @libhydra_plugins@ -libstrongswan_plugins = @libstrongswan_plugins@ 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@ oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ pdfdir = @pdfdir@ piddir = @piddir@ +pki_plugins = @pki_plugins@ plugindir = @plugindir@ pluto_plugins = @pluto_plugins@ +pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ @@ -241,7 +254,10 @@ 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@ srcdir = @srcdir@ strongswan_conf = @strongswan_conf@ diff --git a/src/pluto/pluto.8 b/src/pluto/pluto.8 index b80d13772..58cb15091 100644 --- a/src/pluto/pluto.8 +++ b/src/pluto/pluto.8 @@ -15,7 +15,6 @@ ipsec pluto \fIfilename\fP] [\-\-nofork] [\-\-stderrlog] -[\-\-noklips] [\-\-uniqueids] [\fB\-\-interface\fP \fIinterfacename\fP] [\-\-ikeport\ \c @@ -37,7 +36,7 @@ ipsec pluto [\-\-debug\(hyemitting] [\-\-debug\(hycontrol] [\-\-debug\(hylifecycle] -[\-\-debug\(hyklips] +[\-\-debug\(hykernel] [\-\-debug\(hydns] [\-\-debug\(hyoppo] [\-\-debug\(hyprivate] @@ -209,7 +208,7 @@ ipsec whack [\-\-debug\(hyemitting] [\-\-debug\(hycontrol] [\-\-debug\(hylifecycle] -[\-\-debug\(hyklips] +[\-\-debug\(hykernel] [\-\-debug\(hydns] [\-\-debug\(hyoppo] [\-\-debug\(hyprivate] @@ -256,10 +255,7 @@ In other words, .BR pluto can eliminate much of the work of manual keying. The actual -secure transmission of packets is the responsibility of other parts of -the system (see -.BR KLIPS , -the companion implementation of IPsec). +secure transmission of packets is the responsibility of the Linux kernel. \fIipsec_auto\fP(8) provides a more convenient interface to \fBpluto\fP and \fBwhack\fP. .SS IKE's Job @@ -314,8 +310,8 @@ are considered policy and are left in the system administrator's hands. .SS Pluto .LP \fBpluto\fP is an implementation of IKE. It runs as a daemon on a network -node. Currently, this network node must be a LINUX system running the -\fBKLIPS\fP implementation of IPsec. +node. Currently, this network node must be a Linux 2.6 system running the +native \fBNETKEY\fP IPsec stack. .LP \fBpluto\fP only implements a subset of IKE. This is enough for it to interoperate with other instances of \fBpluto\fP, and many other IKE @@ -331,13 +327,13 @@ peers with whom it is negotiating. .LP \fBpluto\fP initiates negotiation of a Security Association when it is manually prodded: the program \fBwhack\fP is run to trigger this. -It will also initiate a negotiation when \fBKLIPS\fP traps an outbound packet -for Opportunistic Encryption. +It will also initiate a negotiation when the Linux kernel traps an outbound +packet for Opportunistic Encryption. .LP \fBpluto\fP implements ISAKMP SAs itself. After it has negotiated the -characteristics of an IPsec SA, it directs \fBKLIPS\fP to implement it. +characteristics of an IPsec SA, it directs the Linux kernel to implement it. It also invokes a script to adjust any firewall and issue \fIroute\fP(8) -commands to direct IP packets through \fBKLIPS\fP. +commands. .LP When \fBpluto\fP shuts down, it closes all Security Associations. .SS Before Running Pluto @@ -345,8 +341,8 @@ When \fBpluto\fP shuts down, it closes all Security Associations. \fBpluto\fP runs as a daemon with userid root. Before running it, a few things must be set up. .LP -\fBpluto\fP requires \fBKLIPS\fP, the FreeS/WAN implementation of IPsec. -All of the components of \fBKLIPS\fP and \fBpluto\fP should be installed. +\fBpluto\fP requires a Linux 2.6 kernel with the modules for the native IPsec +stack enabled. .LP \fBpluto\fP supports multiple public networks (that is, networks that are considered insecure and thus need to have their traffic @@ -355,11 +351,8 @@ public interfaces to use by looking at all interfaces that are configured (the \fB\-\-interface\fP option can be used to limit the interfaces considered). It does this only when \fBwhack\fP tells it to \-\-listen, -so the interfaces must be configured by then. Each interface with a name of the form -\fBipsec\fP[\fB0\fP-\fB9\fP] is taken as a \fBKLIPS\fP virtual public interface. -Another network interface with the same IP address (there should be only -one) is taken as the corresponding real public -interface. \fIifconfig\fP(8) with the \fB\-a\fP flag will show +so the interfaces must be configured by then. +\fIifconfig\fP(8) with the \fB\-a\fP flag will show the name and status of each network interface. .LP \fBpluto\fP requires a database of preshared secrets and RSA private keys. @@ -368,33 +361,6 @@ This is described in the \fBpluto\fP is told of RSA public keys via \fBwhack\fP commands. If the connection is Opportunistic, and no RSA public key is known, \fBpluto\fP will attempt to fetch RSA keys using the Domain Name System. -.SS Setting up \fBKLIPS\fP for \fBpluto\fP -.LP -The most basic network topology that \fBpluto\fP supports has two security -gateways negotiating on behalf of client subnets. The diagram of RGB's -testbed is a good example (see \fIklips/doc/rgb_setup.txt\fP). -.LP -The file \fIINSTALL\fP in the base directory of this distribution -explains how to start setting up the whole system, including \fBKLIPS\fP. -.LP -Make sure that the security gateways have routes to each other. This -is usually covered by the default route, but may require issuing -.IR route (8) -commands. The route must go through a particular IP -interface (we will assume it is \fIeth0\fP, but it need not be). The -interface that connects the security gateway to its client must be a -different one. -.LP -It is necessary to issue a -.IR ipsec_tncfg (8) -command on each gateway. The required command is: - -\ \ \ ipsec tncfg \-\-attach\ \-\-virtual\ ipsec0 \-\-physical\ eth0 - -A command to set up the ipsec0 virtual interface will also need to be -run. It will have the same parameters as the command used to set up -the physical interface to which it has just been connected using -.IR ipsec_tncfg (8). .SS ipsec.secrets file .LP A \fBpluto\fP daemon and another IKE daemon (for example, another instance @@ -473,13 +439,6 @@ corresponding to a particular connection. Often there is one representing an ISAKMP SA and another representing an IPsec SA. .LP -\fBKLIPS\fP hooks into the routing code in a LINUX kernel. -Traffic to be processed by an IPsec SA must be directed through -\fBKLIPS\fP by routing commands. Furthermore, the processing to be -done is specified by \fIipsec eroute(8)\fP commands. -\fBpluto\fP takes the responsibility of managing both of these special -kinds of routes. -.LP Each connection may be routed, and must be while it has an IPsec SA. The connection specifies the characteristics of the route: the interface on this machine, the ``gateway'' (the nexthop), @@ -519,9 +478,9 @@ SA for the same connection already has an eroute, all its outgoing traffic is taken over by the new eroute. The incoming traffic will still be processed. This characteristic is exploited during rekeying. .LP -All of these routing characteristics are expected change when -\fBKLIPS\fP is modified to use the firewall hooks in the LINUX 2.4.x -kernel. +Some of these routing characteristics are specific to \fBKLIPS\fP, the FreeS/WAN +implementation of IPsec and are not relevant when running pluto on the native +Linux 2.6 IPsec stack. .SS Using Whack .LP \fBwhack\fP is used to command a running \fBpluto\fP. @@ -691,7 +650,7 @@ Note that this has nothing to do with IKE authentication. .TP \fB\-\-compress\fP All proposed IPsec SAs will include IPCOMP (compression). -This will be ignored if KLIPS is not configured with IPCOMP support. +This will be ignored if the kernel is not configured with IPCOMP support. .TP \fB\-\-tunnel\fP the IPsec SA should use tunneling. Implicit if the SA is for clients. @@ -1304,9 +1263,6 @@ disable ``daemon fork'' (default is to fork). In addition, after the lock file and control socket are created, print the line ``Pluto initialized'' to standard out. .TP -\fB\-\-noklips\fP -don't actually implement negotiated IPsec SAs -.TP \fB\-\-uniqueids\fP if this option has been selected, whenever a new ISAKMP SA is established, any connection with the same Peer ID but a different @@ -1317,12 +1273,6 @@ then regained at another IP address. \fB\-\-stderrlog\fP log goes to standard out {default is to use \fIsyslogd\fP(8)) .LP -For example -.TP -pluto \-\-secretsfile\ ipsec.secrets \-\-ctlbase\ pluto.base \-\-ikeport\ 8500 \-\-nofork \-\-noklips \-\-stderrlog -.LP -lets one test \fBpluto\fP without using the superuser account. -.LP \fBpluto\fP is willing to produce a prodigious amount of debugging information. To do so, it must be compiled with \-DDEBUG. There are several classes of debugging output, and \fBpluto\fP may be directed to @@ -1351,8 +1301,8 @@ show \fBpluto\fP's decision making \fB\-\-debug-lifecycle\fP [this option is temporary] log more detail of lifecycle of SAs .TP -\fB\-\-debug-klips\fP -show \fBpluto\fP's interaction with \fBKLIPS\fP +\fB\-\-debug-kernel\fP +show \fBpluto\fP's interaction with the kernel .TP \fB\-\-debug-dns\fP show \fBpluto\fP's interaction with \fBDNS\fP for KEY and TXT records @@ -1418,11 +1368,6 @@ system (\fBpluto\fP didn't send a reply because it wasn't happy with the previous message). .SS Notes .LP -If \fBpluto\fP is compiled without \-DKLIPS, it negotiates Security -Associations but never ask the kernel to put them in place and never -makes routing changes. This allows \fBpluto\fP to be tested on systems -without \fBKLIPS\fP, but makes it rather useless. -.LP Each IPsec SA is assigned an SPI, a 32-bit number used to refer to the SA. The IKE protocol lets the destination of the SA choose the SPI. The range 0 to 0xFF is reserved for IANA. @@ -1469,7 +1414,7 @@ component. The selection is controlled by the \-\-encrypt and .IP \(bu Each of these may be combined with IPCOMP Deflate compression, but only if the potential connection specifies compression and only -if KLIPS is configured with IPCOMP support. +if the kernel is configured with IPCOMP support. .IP \(bu The IPSEC SAs may be tunnel or transport mode, where appropriate. The \-\-tunnel flag controls this when \fBpluto\fP is initiating. diff --git a/src/pluto/pluto.c b/src/pluto/pluto.c index e9c7c316b..66fdb30b9 100644 --- a/src/pluto/pluto.c +++ b/src/pluto/pluto.c @@ -41,6 +41,7 @@ pluto_t *pluto; void pluto_deinit() { private_pluto_t *this = (private_pluto_t*)pluto; + this->public.events->destroy(this->public.events); this->public.xauth->destroy(this->public.xauth); free(this); pluto = NULL; @@ -55,6 +56,7 @@ bool pluto_init(char *file) INIT(this, .public = { + .events = event_queue_create(), .xauth = xauth_manager_create(), }, ); diff --git a/src/pluto/pluto.h b/src/pluto/pluto.h index 37e6e3f33..2440093ca 100644 --- a/src/pluto/pluto.h +++ b/src/pluto/pluto.h @@ -31,6 +31,7 @@ typedef struct pluto_t pluto_t; +#include <event_queue.h> #include <xauth/xauth_manager.h> #include <library.h> @@ -41,9 +42,15 @@ typedef struct pluto_t pluto_t; struct pluto_t { /** + * event queue (callbacks, executed by the pluto main thread) + */ + event_queue_t *events; + + /** * manager for payload attributes */ xauth_manager_t *xauth; + }; /** diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c index 89123bb8a..627176c1b 100644 --- a/src/pluto/plutomain.c +++ b/src/pluto/plutomain.c @@ -79,6 +79,11 @@ #include "whack_attribute.h" #include "pluto.h" +/** + * Number of threads in the thread pool, if not specified in config. + */ +#define DEFAULT_THREADS 4 + static void usage(const char *mess) { if (mess != NULL && *mess != '\0') @@ -91,7 +96,6 @@ static void usage(const char *mess) " \\\n\t" "[--nofork]" " [--stderrlog]" - " [--noklips]" " [--nocrsend]" " \\\n\t" "[--strictcrlpolicy]" @@ -125,7 +129,7 @@ static void usage(const char *mess) " \\\n\t" "[--debug-control]" " [--debug-lifecycle]" - " [--debug-klips]" + " [--debug-kernel]" " [--debug-dns]" " \\\n\t" "[--debug-oppo]" @@ -295,7 +299,6 @@ int main(int argc, char **argv) { "optionsfrom", required_argument, NULL, '+' }, { "nofork", no_argument, NULL, 'd' }, { "stderrlog", no_argument, NULL, 'e' }, - { "noklips", no_argument, NULL, 'n' }, { "nocrsend", no_argument, NULL, 'c' }, { "strictcrlpolicy", no_argument, NULL, 'r' }, { "crlcheckinterval", required_argument, NULL, 'x'}, @@ -333,7 +336,8 @@ int main(int argc, char **argv) { "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET }, { "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET }, { "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET }, - { "debug-klips", no_argument, NULL, DBG_KLIPS + DBG_OFFSET }, + { "debug-klips", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, + { "debug-kernel", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET }, { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET }, { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET }, @@ -396,10 +400,6 @@ int main(int argc, char **argv) log_to_stderr_desired = TRUE; continue; - case 'n': /* --noklips */ - no_klips = TRUE; - continue; - case 'c': /* --nocrsend */ no_cr_send = TRUE; continue; @@ -621,27 +621,19 @@ int main(int argc, char **argv) fflush(stdout); } - /* Close everything but ctl_fd and (if needed) stderr. - * There is some danger that a library that we don't know - * about is using some fd that we don't know about. - * I guess we'll soon find out. + /* Redirect stdin, stdout and stderr to /dev/null */ { - int i; - - for (i = getdtablesize() - 1; i >= 0; i--) /* Bad hack */ - { - if ((!log_to_stderr || i != 2) && i != ctl_fd) - close(i); - } - - /* make sure that stdin, stdout, stderr are reserved */ - if (open("/dev/null", O_RDONLY) != 0) + int fd; + if ((fd = open("/dev/null", O_RDWR)) == -1) + abort(); + if (dup2(fd, 0) != 0) abort(); - if (dup2(0, 1) != 1) + if (dup2(fd, 1) != 1) abort(); - if (!log_to_stderr && dup2(0, 2) != 2) + if (!log_to_stderr && dup2(fd, 2) != 2) abort(); + close(fd); } init_constants(); @@ -764,6 +756,10 @@ int main(int argc, char **argv) /* loading attribute certificates (experimental) */ ac_load_certs(); + lib->processor->set_threads(lib->processor, + lib->settings->get_int(lib->settings, "pluto.threads", + DEFAULT_THREADS)); + daily_log_event(); call_server(); return -1; /* Shouldn't ever reach this */ @@ -779,11 +775,13 @@ int main(int argc, char **argv) */ void exit_pluto(int status) { + lib->processor->set_threads(lib->processor, 0); reset_globals(); /* needed because we may be called in odd state */ free_preshared_secrets(); free_remembered_public_keys(); delete_every_connection(); whack_attribute_finalize(); /* free in-memory pools */ + kernel_finalize(); fetch_finalize(); /* stop fetching thread */ free_crl_fetch(); /* free chain of crl fetch requests */ free_ocsp_fetch(); /* free chain of ocsp fetch requests */ diff --git a/src/pluto/server.c b/src/pluto/server.c index 21f65f4f8..4d07843c1 100644 --- a/src/pluto/server.c +++ b/src/pluto/server.c @@ -56,6 +56,7 @@ #include "adns.h" /* needs <resolv.h> */ #include "dnskey.h" /* needs keys.h and adns.h */ #include "whack.h" /* for RC_LOG_SERIOUS */ +#include "pluto.h" #include <pfkeyv2.h> #include <pfkey.h> @@ -467,7 +468,6 @@ create_socket(struct raw_iface *ifp, const char *v_name, int port) #endif #if defined(linux) && defined(KERNEL26_SUPPORT) - if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) { struct sadb_x_policy policy; int level, opt; @@ -536,7 +536,6 @@ process_raw_ifaces(struct raw_iface *rifaces) for (ifp = rifaces; ifp != NULL; ifp = ifp->next) { struct raw_iface *v = NULL; /* matching ipsecX interface */ - struct raw_iface fake_v; bool after = FALSE; /* has vfp passed ifp on the list? */ bool bad = FALSE; struct raw_iface *vfp; @@ -578,7 +577,6 @@ process_raw_ifaces(struct raw_iface *rifaces) * "after" allows us to avoid double reporting. */ #if defined(linux) && defined(KERNEL26_SUPPORT) - if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) { if (after) { @@ -603,7 +601,6 @@ process_raw_ifaces(struct raw_iface *rifaces) continue; #if defined(linux) && defined(KERNEL26_SUPPORT) - if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) { v = ifp; goto add_entry; @@ -613,24 +610,10 @@ process_raw_ifaces(struct raw_iface *rifaces) /* what if we didn't find a virtual interface? */ if (v == NULL) { - if (no_klips) - { - /* kludge for testing: invent a virtual device */ - static const char fvp[] = "virtual"; - fake_v = *ifp; - passert(sizeof(fake_v.name) > sizeof(fvp)); - strcpy(fake_v.name, fvp); - addrtot(&ifp->addr, 0, fake_v.name + sizeof(fvp) - 1 - , sizeof(fake_v.name) - (sizeof(fvp) - 1)); - v = &fake_v; - } - else - { - DBG(DBG_CONTROL, - DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored" - , ifp->name, ip_str(&ifp->addr))); - continue; - } + DBG(DBG_CONTROL, + DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored" + , ifp->name, ip_str(&ifp->addr))); + continue; } /* We've got all we need; see if this is a new thing: @@ -811,7 +794,7 @@ call_server(void) { fd_set readfds; fd_set writefds; - int ndes; + int ndes, events_fd; /* wait for next interesting thing */ @@ -853,19 +836,10 @@ call_server(void) FD_SET(adns_afd, &readfds); } -#ifdef KLIPS - if (!no_klips) - { - int fd = *kernel_ops->async_fdp; - - if (kernel_ops->process_queue) - kernel_ops->process_queue(); - if (maxfd < fd) - maxfd = fd; - passert(!FD_ISSET(fd, &readfds)); - FD_SET(fd, &readfds); - } -#endif + events_fd = pluto->events->get_event_fd(pluto->events); + if (maxfd < events_fd) + maxfd = events_fd; + FD_SET(events_fd, &readfds); if (listening) { @@ -947,18 +921,16 @@ call_server(void) ndes--; } -#ifdef KLIPS - if (!no_klips && FD_ISSET(*kernel_ops->async_fdp, &readfds)) + if (FD_ISSET(events_fd, &readfds)) { passert(ndes > 0); DBG(DBG_CONTROL, DBG_log(BLANK_FORMAT); - DBG_log("*received kernel message")); - kernel_ops->process_msg(); + DBG_log("*handling asynchronous events")); + pluto->events->handle(pluto->events); passert(GLOBALS_ARE_RESET()); ndes--; } -#endif for (ifp = interfaces; ifp != NULL; ifp = ifp->next) { diff --git a/src/pluto/smartcard.c b/src/pluto/smartcard.c index f1a3932a6..85e246ac4 100644 --- a/src/pluto/smartcard.c +++ b/src/pluto/smartcard.c @@ -502,9 +502,9 @@ static cert_t* scx_find_cert_object(CK_SESSION_HANDLE session, *cert = cert_empty; cert->smartcard = TRUE; cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_END); if (cert->cert) { return cert; @@ -539,6 +539,7 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) CK_ULONG obj_count = 0; time_t valid_until; smartcard_t *sc; + cert_t *cert; certificate_t *certificate; x509_t *x509; @@ -559,8 +560,8 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) *sc = empty_sc; sc->any_slot = FALSE; sc->slot = slot; - sc->last_cert = scx_find_cert_object(session, object, sc); - if (sc->last_cert == NULL) + cert = scx_find_cert_object(session, object, sc); + if (!cert) { scx_free(sc); continue; @@ -571,9 +572,10 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) ) /* check validity of certificate */ - certificate = sc->last_cert->cert; + certificate = cert->cert; if (!certificate->get_validity(certificate, NULL, NULL, &valid_until)) { + cert_free(cert); scx_free(sc); continue; } @@ -582,17 +584,17 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) ) sc = scx_add(sc); - x509 = (x509_t*)certificate; /* put end entity and ca certificates into different chains */ + x509 = (x509_t*)certificate; if (x509->get_flags(x509) & X509_CA) { - sc->last_cert = add_authcert(sc->last_cert, X509_CA); + sc->last_cert = add_authcert(cert, X509_CA); } else { - add_public_key_from_cert(sc->last_cert, valid_until, DAL_LOCAL); - sc->last_cert = cert_add(sc->last_cert); + add_public_key_from_cert(cert, valid_until, DAL_LOCAL); + sc->last_cert = cert_add(cert); } cert_share(sc->last_cert); @@ -1078,7 +1080,7 @@ cert_t* scx_load_cert(const char *filename, smartcard_t **scp, bool *cached) *scp = sc = scx_add(scx_parse_number_slot_id(number_slot_id)); /* is there a cached smartcard certificate? */ - *cached = sc->last_cert && + *cached = sc->last_cert && (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL; if (*cached) @@ -1451,7 +1453,7 @@ bool scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, { return FALSE; } - key->encrypt(key, plain_text, &cipher_text); + key->encrypt(key, ENCRYPT_RSA_PKCS1, plain_text, &cipher_text); key->destroy(key); if (cipher_text.ptr == NULL) diff --git a/src/pluto/spdb.c b/src/pluto/spdb.c index cdf2cb21b..2ed07bdfc 100644 --- a/src/pluto/spdb.c +++ b/src/pluto/spdb.c @@ -234,7 +234,7 @@ out_attr(int type , val, enum_show(d, val))); return TRUE; } -#define return_on(var, val) do { var=val;goto return_out; } while(0); +#define return_on(var, val) do { var=val;goto return_out; } while(0) /* Output an SA, as described by a db_sa. * This has the side-effect of allocating SPIs for us. */ @@ -448,7 +448,7 @@ out_sa(pb_stream *outs , &st->st_connection->spd , tunnel_mode); if (*spi_ptr == 0) - return FALSE; + return_on(ret, FALSE); *spi_generated = TRUE; } if (!out_raw((u_char *)spi_ptr, IPSEC_DOI_SPI_SIZE @@ -2176,7 +2176,7 @@ parse_ipsec_sa_body( #endif if (!can_do_IPcomp) { - plog("compression proposed by %s, but KLIPS is not configured with IPCOMP" + plog("compression proposed by %s, but kernel does not support IPCOMP" , ip_str(&c->spd.that.host_addr)); continue; } diff --git a/src/pluto/state.c b/src/pluto/state.c index 29d78fb3d..3639f944d 100644 --- a/src/pluto/state.c +++ b/src/pluto/state.c @@ -734,7 +734,7 @@ void fmt_state(bool all, struct state *st, time_t n, char *state_buf, , st->st_serialno , c->name, inst , enum_name(&state_names, st->st_state) - , state_story[st->st_state - STATE_MAIN_R0] + , state_story[st->st_state] , timer_event_names, st->st_event->ev_type , delta , np1, np2, eo, dpd); @@ -782,7 +782,7 @@ void fmt_state(bool all, struct state *st, time_t n, char *state_buf, } if (st->st_esp.present) { - time_t now = time(NULL); + time_t now = time_monotonic(NULL); add_said(&c->spd.that.host_addr, st->st_esp.attrs.spi, SA_ESP); add_sa_info(st, FALSE); @@ -794,12 +794,10 @@ void fmt_state(bool all, struct state *st, time_t n, char *state_buf, add_said(&c->spd.that.host_addr, st->st_ipcomp.attrs.spi, SA_COMP); add_said(&c->spd.this.host_addr, st->st_ipcomp.our_spi, SA_COMP); } -#ifdef KLIPS tunnel = st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; p += snprintf(p, p_end - p, "; %s", tunnel? "tunnel":"transport"); -#endif snprintf(state_buf2, state_buf2_len , "#%lu: \"%s\"%s%s" @@ -897,56 +895,6 @@ void show_states_status(bool all, const char *name) free(array); } -/* Given that we've used up a range of unused CPI's, - * search for a new range of currently unused ones. - * Note: this is very expensive when not trivial! - * If we can't find one easily, choose 0 (a bad SPI, - * no matter what order) indicating failure. - */ -void find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi) -{ - int tries = 0; - cpi_t base = *latest_cpi; - cpi_t closest; - int i; - -startover: - closest = ~0; /* not close at all */ - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - struct state *st; - - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - { - if (st->st_ipcomp.present) - { - cpi_t c = ntohl(st->st_ipcomp.our_spi) - base; - - if (c < closest) - { - if (c == 0) - { - /* oops: next spot is occupied; start over */ - if (++tries == 20) - { - /* FAILURE */ - *latest_cpi = *first_busy_cpi = 0; - return; - } - base++; - if (base > IPCOMP_LAST_NEGOTIATED) - base = IPCOMP_FIRST_NEGOTIATED; - goto startover; /* really a tail call */ - } - closest = c; - } - } - } - } - *latest_cpi = base; /* base is first in next free range */ - *first_busy_cpi = closest + base; /* and this is the roof */ -} - /* Muck with high-order 16 bits of this SPI in order to make * the corresponding SAID unique. * Its low-order 16 bits hold a well-known IPCOMP CPI. diff --git a/src/pluto/state.h b/src/pluto/state.h index c4e8db485..a307d9f69 100644 --- a/src/pluto/state.h +++ b/src/pluto/state.h @@ -127,10 +127,8 @@ struct state struct ipsec_proto_info st_ah; struct ipsec_proto_info st_esp; struct ipsec_proto_info st_ipcomp; -#ifdef KLIPS ipsec_spi_t st_tunnel_in_spi; /* KLUDGE */ ipsec_spi_t st_tunnel_out_spi; /* KLUDGE */ -#endif const struct dh_desc *st_pfs_group; /* group for Phase 2 PFS */ @@ -267,7 +265,6 @@ extern struct state extern void show_states_status(bool all, const char *name); extern void for_each_state(void *(f)(struct state *, void *data), void *data); -extern void find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi); extern ipsec_spi_t uniquify_his_cpi(ipsec_spi_t cpi, struct state *st); extern void fmt_state(bool all, struct state *st, time_t n , char *state_buf, size_t state_buf_len diff --git a/src/pluto/timer.c b/src/pluto/timer.c index b112d67f6..c1ad55f5e 100644 --- a/src/pluto/timer.c +++ b/src/pluto/timer.c @@ -233,13 +233,6 @@ void handle_timer_event(void) init_secret(); break; -#ifdef KLIPS - case EVENT_SHUNT_SCAN: - passert(st == NULL); - scan_proc_shunts(); - break; -#endif - case EVENT_LOG_DAILY: daily_log_event(); break; diff --git a/src/pluto/x509.c b/src/pluto/x509.c index 2b8681246..d717beb15 100644 --- a/src/pluto/x509.c +++ b/src/pluto/x509.c @@ -427,7 +427,7 @@ void list_x509cert_chain(const char *caption, cert_t* cert, { whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", key_type_names, key->get_type(key), - key->get_keysize(key) * BITS_PER_BYTE, + key->get_keysize(key), cert->smartcard ? ", on smartcard" : (has_private_key(cert)? ", has private key" : "")); |