diff options
Diffstat (limited to 'src/charon/plugins/kernel_pfkey')
-rw-r--r-- | src/charon/plugins/kernel_pfkey/Makefile.am | 2 | ||||
-rw-r--r-- | src/charon/plugins/kernel_pfkey/Makefile.in | 7 | ||||
-rw-r--r-- | src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 192 |
3 files changed, 180 insertions, 21 deletions
diff --git a/src/charon/plugins/kernel_pfkey/Makefile.am b/src/charon/plugins/kernel_pfkey/Makefile.am index c9d66b5de..e03a0ca02 100644 --- a/src/charon/plugins/kernel_pfkey/Makefile.am +++ b/src/charon/plugins/kernel_pfkey/Makefile.am @@ -7,4 +7,4 @@ plugin_LTLIBRARIES = libstrongswan-kernel-pfkey.la libstrongswan_kernel_pfkey_la_SOURCES = kernel_pfkey_plugin.h kernel_pfkey_plugin.c \ kernel_pfkey_ipsec.h kernel_pfkey_ipsec.c -libstrongswan_kernel_pfkey_la_LDFLAGS = -module +libstrongswan_kernel_pfkey_la_LDFLAGS = -module -avoid-version diff --git a/src/charon/plugins/kernel_pfkey/Makefile.in b/src/charon/plugins/kernel_pfkey/Makefile.in index df2492ef7..e01510127 100644 --- a/src/charon/plugins/kernel_pfkey/Makefile.in +++ b/src/charon/plugins/kernel_pfkey/Makefile.in @@ -76,12 +76,14 @@ ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ @@ -146,6 +148,7 @@ RUBYINCLUDE = @RUBYINCLUDE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ @@ -186,7 +189,9 @@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ ipsecdir = @ipsecdir@ +ipsecgid = @ipsecgid@ ipsecgroup = @ipsecgroup@ +ipsecuid = @ipsecuid@ ipsecuser = @ipsecuser@ libdir = @libdir@ libexecdir = @libexecdir@ @@ -226,7 +231,7 @@ plugin_LTLIBRARIES = libstrongswan-kernel-pfkey.la libstrongswan_kernel_pfkey_la_SOURCES = kernel_pfkey_plugin.h kernel_pfkey_plugin.c \ kernel_pfkey_ipsec.h kernel_pfkey_ipsec.c -libstrongswan_kernel_pfkey_la_LDFLAGS = -module +libstrongswan_kernel_pfkey_la_LDFLAGS = -module -avoid-version all: all-am .SUFFIXES: diff --git a/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 56f0320dc..1f83e8f39 100644 --- a/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -17,6 +17,10 @@ #include <sys/types.h> #include <sys/socket.h> +#ifdef __FreeBSD__ +#include <limits.h> /* for LONG_MAX */ +#endif + #ifdef HAVE_NET_PFKEYV2_H #include <net/pfkeyv2.h> #else @@ -37,11 +41,11 @@ #endif #ifdef HAVE_NATT -#ifdef HAVE_NETINET_UDP_H -#include <netinet/udp.h> -#else +#ifdef HAVE_LINUX_UDP_H #include <linux/udp.h> -#endif /*HAVE_NETINET_UDP_H*/ +#else +#include <netinet/udp.h> +#endif /*HAVE_LINUX_UDP_H*/ #endif /*HAVE_NATT*/ #include <unistd.h> @@ -89,7 +93,7 @@ #define IP_IPSEC_POLICY 16 #endif -/* missing on uclibc */ +/** missing on uclibc */ #ifndef IPV6_IPSEC_POLICY #define IPV6_IPSEC_POLICY 34 #endif @@ -98,6 +102,17 @@ #define PRIO_LOW 3000 #define PRIO_HIGH 2000 +#ifdef __APPLE__ +/** from xnu/bsd/net/pfkeyv2.h */ +#define SADB_X_EXT_NATT 0x002 + struct sadb_sa_2 { + struct sadb_sa sa; + u_int16_t sadb_sa_natt_port; + u_int16_t sadb_reserved0; + u_int32_t sadb_reserved1; + }; +#endif + /** buffer size for PF_KEY messages */ #define PFKEY_BUFFER_SIZE 4096 @@ -467,7 +482,7 @@ static u_int8_t dir2kernel(policy_dir_t dir) return IPSEC_DIR_FWD; #endif default: - return dir; + return IPSEC_DIR_INVALID; } } @@ -693,7 +708,7 @@ static status_t parse_pfkey_message(struct sadb_msg *msg, pfkey_msg_t *out) while (len >= PFKEY_LEN(sizeof(struct sadb_ext))) { - DBG2(DBG_KNL, " %N", sadb_ext_type_names, ext->sadb_ext_type); + DBG3(DBG_KNL, " %N", sadb_ext_type_names, ext->sadb_ext_type); if (ext->sadb_ext_len < PFKEY_LEN(sizeof(struct sadb_ext)) || ext->sadb_ext_len > len) { @@ -740,6 +755,8 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket this->mutex_pfkey->lock(this->mutex_pfkey); + /* FIXME: our usage of sequence numbers is probably wrong. check RFC 2367, + * in particular the behavior in response to an SADB_ACQUIRE. */ in->sadb_msg_seq = ++this->seq; in->sadb_msg_pid = getpid(); @@ -801,14 +818,23 @@ static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket } if (msg->sadb_msg_seq != this->seq) { - DBG1(DBG_KNL, "received PF_KEY message with invalid sequence number, " - "was %d expected %d", msg->sadb_msg_seq, this->seq); - if (msg->sadb_msg_seq < this->seq) + DBG1(DBG_KNL, "received PF_KEY message with unexpected sequence " + "number, was %d expected %d", msg->sadb_msg_seq, this->seq); + if (msg->sadb_msg_seq == 0) + { + /* FreeBSD and Mac OS X do this for the response to + * SADB_X_SPDGET (but not for the response to SADB_GET). + * FreeBSD: 'key_spdget' in /usr/src/sys/netipsec/key.c. */ + } + else if (msg->sadb_msg_seq < this->seq) { continue; } - this->mutex_pfkey->unlock(this->mutex_pfkey); - return FAILED; + else + { + this->mutex_pfkey->unlock(this->mutex_pfkey); + return FAILED; + } } if (msg->sadb_msg_type != in->sadb_msg_type) { @@ -1223,10 +1249,25 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this, msg->sadb_msg_type = inbound ? SADB_UPDATE : SADB_ADD; msg->sadb_msg_satype = proto_ike2satype(protocol); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); - - sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); + +#ifdef __APPLE__ + if (encap) + { + struct sadb_sa_2 *sa_2; + sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg); + sa_2->sadb_sa_natt_port = dst->get_port(dst); + sa = &sa_2->sa; + sa->sadb_sa_flags |= SADB_X_EXT_NATT; + len = sizeof(struct sadb_sa_2); + } + else +#endif + { + sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); + len = sizeof(struct sadb_sa); + } sa->sadb_sa_exttype = SADB_EXT_SA; - sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); + sa->sadb_sa_len = PFKEY_LEN(len); sa->sadb_sa_spi = spi; sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32; sa->sadb_sa_auth = lookup_algorithm(integrity_algs, int_alg); @@ -1403,7 +1444,21 @@ static status_t update_sa(private_kernel_pfkey_ipsec_t *this, msg->sadb_msg_satype = proto_ike2satype(protocol); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); +#ifdef __APPLE__ + { + struct sadb_sa_2 *sa_2; + sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg); + sa_2->sa.sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa_2)); + memcpy(&sa_2->sa, response.sa, sizeof(struct sadb_sa)); + if (encap) + { + sa_2->sadb_sa_natt_port = new_dst->get_port(new_dst); + sa_2->sa.sadb_sa_flags |= SADB_X_EXT_NATT; + } + } +#else PFKEY_EXT_COPY(msg, response.sa); +#endif PFKEY_EXT_COPY(msg, response.x_sa2); PFKEY_EXT_COPY(msg, response.src); @@ -1421,7 +1476,7 @@ static status_t update_sa(private_kernel_pfkey_ipsec_t *this, { PFKEY_EXT_COPY(msg, response.key_auth); } - + #ifdef HAVE_NATT if (new_encap) { @@ -1449,6 +1504,65 @@ static status_t update_sa(private_kernel_pfkey_ipsec_t *this, } /** + * Implementation of kernel_interface_t.query_sa. + */ +static status_t query_sa(private_kernel_pfkey_ipsec_t *this, host_t *src, + host_t *dst, u_int32_t spi, protocol_id_t protocol, + u_int64_t *bytes) +{ + unsigned char request[PFKEY_BUFFER_SIZE]; + struct sadb_msg *msg, *out; + struct sadb_sa *sa; + pfkey_msg_t response; + size_t len; + + memset(&request, 0, sizeof(request)); + + DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi)); + + msg = (struct sadb_msg*)request; + msg->sadb_msg_version = PF_KEY_V2; + msg->sadb_msg_type = SADB_GET; + msg->sadb_msg_satype = proto_ike2satype(protocol); + msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); + + sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); + sa->sadb_sa_exttype = SADB_EXT_SA; + sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); + sa->sadb_sa_spi = spi; + PFKEY_EXT_ADD(msg, sa); + + /* the Linux Kernel doesn't care for the src address, but other systems do + * (e.g. FreeBSD) + */ + add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0); + add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0); + + if (pfkey_send(this, msg, &out, &len) != SUCCESS) + { + DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi)); + return FAILED; + } + else if (out->sadb_msg_errno) + { + DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)", + ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno); + free(out); + return FAILED; + } + else if (parse_pfkey_message(out, &response) != SUCCESS) + { + DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi)); + free(out); + return FAILED; + } + *bytes = response.lft_current->sadb_lifetime_bytes; + + free(out); + return SUCCESS; +} + +/** * Implementation of kernel_interface_t.del_sa. */ static status_t del_sa(private_kernel_pfkey_ipsec_t *this, host_t *src, @@ -1476,7 +1590,9 @@ static status_t del_sa(private_kernel_pfkey_ipsec_t *this, host_t *src, sa->sadb_sa_spi = spi; PFKEY_EXT_ADD(msg, sa); - /* the Linux Kernel doesn't care for the src address, but other systems do (e.g. FreeBSD) */ + /* the Linux Kernel doesn't care for the src address, but other systems do + * (e.g. FreeBSD) + */ add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0); add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0); @@ -1518,6 +1634,12 @@ static status_t add_policy(private_kernel_pfkey_ipsec_t *this, pfkey_msg_t response; size_t len; + if (dir2kernel(direction) == IPSEC_DIR_INVALID) + { + /* FWD policies are not supported on all platforms */ + return SUCCESS; + } + /* create a policy */ policy = create_policy_entry(src_ts, dst_ts, direction, reqid); @@ -1594,6 +1716,18 @@ static status_t add_policy(private_kernel_pfkey_ipsec_t *this, add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto, policy->dst.mask); +#ifdef __FreeBSD__ + { /* on FreeBSD a lifetime has to be defined to be able to later query + * the current use time. */ + struct sadb_lifetime *lft; + lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); + lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime)); + lft->sadb_lifetime_addtime = LONG_MAX; + PFKEY_EXT_ADD(msg, lft); + } +#endif + this->mutex->unlock(this->mutex); if (pfkey_send(this, msg, &out, &len) != SUCCESS) @@ -1700,6 +1834,12 @@ static status_t query_policy(private_kernel_pfkey_ipsec_t *this, pfkey_msg_t response; size_t len; + if (dir2kernel(direction) == IPSEC_DIR_INVALID) + { + /* FWD policies are not supported on all platforms */ + return NOT_FOUND; + } + DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts, policy_dir_names, direction); @@ -1764,6 +1904,13 @@ static status_t query_policy(private_kernel_pfkey_ipsec_t *this, free(out); return FAILED; } + else if (response.lft_current == NULL) + { + DBG1(DBG_KNL, "unable to query policy %R === %R %N: kernel reports no " + "use time", src_ts, dst_ts, policy_dir_names, direction); + free(out); + return FAILED; + } *use_time = response.lft_current->sadb_lifetime_usetime; @@ -1787,6 +1934,12 @@ static status_t del_policy(private_kernel_pfkey_ipsec_t *this, route_entry_t *route; size_t len; + if (dir2kernel(direction) == IPSEC_DIR_INVALID) + { + /* FWD policies are not supported on all platforms */ + return SUCCESS; + } + DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts, policy_dir_names, direction); @@ -1995,6 +2148,7 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi; this->public.interface.add_sa = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool))add_sa; this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,u_int16_t,host_t*,host_t*,host_t*,host_t*,bool,bool))update_sa; + this->public.interface.query_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int64_t*))query_sa; this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int16_t))del_sa; this->public.interface.add_policy = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t,protocol_id_t,u_int32_t,ipsec_mode_t,u_int16_t,u_int16_t,bool))add_policy; this->public.interface.query_policy = (status_t(*)(kernel_ipsec_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy; @@ -2004,8 +2158,8 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() /* private members */ this->policies = linked_list_create(); - this->mutex = mutex_create(MUTEX_DEFAULT); - this->mutex_pfkey = mutex_create(MUTEX_DEFAULT); + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); + this->mutex_pfkey = mutex_create(MUTEX_TYPE_DEFAULT); this->install_routes = lib->settings->get_bool(lib->settings, "charon.install_routes", TRUE); this->seq = 0; |