diff options
Diffstat (limited to 'src/charon/plugins/kernel_netlink')
4 files changed, 145 insertions, 85 deletions
diff --git a/src/charon/plugins/kernel_netlink/Makefile.in b/src/charon/plugins/kernel_netlink/Makefile.in index 658e0feea..b3b161315 100644 --- a/src/charon/plugins/kernel_netlink/Makefile.in +++ b/src/charon/plugins/kernel_netlink/Makefile.in @@ -88,22 +88,17 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DSYMUTIL = @DSYMUTIL@ -ECHO = @ECHO@ +DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ GPERF = @GPERF@ GREP = @GREP@ INSTALL = @INSTALL@ @@ -113,6 +108,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ @@ -121,12 +117,16 @@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LINUX_HEADERS = @LINUX_HEADERS@ +LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ +NM = @NM@ NMEDIT = @NMEDIT@ OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ @@ -149,8 +149,7 @@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -189,6 +188,7 @@ libstrongswan_plugins = @libstrongswan_plugins@ linuxdir = @linuxdir@ localedir = @localedir@ localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 70a0b3e7c..8a13ed489 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -17,7 +17,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: kernel_netlink_ipsec.c 4662 2008-11-16 21:19:58Z andreas $ + * $Id: kernel_netlink_ipsec.c 4831 2009-01-09 09:37:13Z andreas $ */ #include <sys/types.h> @@ -39,7 +39,7 @@ #include <daemon.h> #include <utils/mutex.h> -#include <utils/linked_list.h> +#include <utils/hashtable.h> #include <processing/jobs/callback_job.h> #include <processing/jobs/acquire_job.h> #include <processing/jobs/migrate_job.h> @@ -57,6 +57,11 @@ #define IP_IPSEC_POLICY 16 #endif +/* missing on uclibc */ +#ifndef IPV6_IPSEC_POLICY +#define IPV6_IPSEC_POLICY 34 +#endif /*IPV6_IPSEC_POLICY*/ + /** default priority of installed policies */ #define PRIO_LOW 3000 #define PRIO_HIGH 2000 @@ -92,13 +97,39 @@ struct kernel_algorithm_t { * Identifier specified in IKEv2 */ int ikev2; - + /** * Name of the algorithm in linux crypto API */ char *name; }; +ENUM(xfrm_msg_names, XFRM_MSG_NEWSA, XFRM_MSG_MAPPING, + "XFRM_MSG_NEWSA", + "XFRM_MSG_DELSA", + "XFRM_MSG_GETSA", + "XFRM_MSG_NEWPOLICY", + "XFRM_MSG_DELPOLICY", + "XFRM_MSG_GETPOLICY", + "XFRM_MSG_ALLOCSPI", + "XFRM_MSG_ACQUIRE", + "XFRM_MSG_EXPIRE", + "XFRM_MSG_UPDPOLICY", + "XFRM_MSG_UPDSA", + "XFRM_MSG_POLEXPIRE", + "XFRM_MSG_FLUSHSA", + "XFRM_MSG_FLUSHPOLICY", + "XFRM_MSG_NEWAE", + "XFRM_MSG_GETAE", + "XFRM_MSG_REPORT", + "XFRM_MSG_MIGRATE", + "XFRM_MSG_NEWSADINFO", + "XFRM_MSG_GETSADINFO", + "XFRM_MSG_NEWSPDINFO", + "XFRM_MSG_GETSPDINFO", + "XFRM_MSG_MAPPING" +); + ENUM(xfrm_attr_type_names, XFRMA_UNSPEC, XFRMA_KMADDRESS, "XFRMA_UNSPEC", "XFRMA_ALG_AUTH", @@ -245,6 +276,24 @@ struct policy_entry_t { u_int refcount; }; +/** + * Hash function for policy_entry_t objects + */ +static u_int policy_hash(policy_entry_t *key) +{ + chunk_t chunk = chunk_create((void*)&key->sel, sizeof(struct xfrm_selector)); + return chunk_hash(chunk); +} + +/** + * Equality function for policy_entry_t objects + */ +static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key) +{ + return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) && + key->direction == other_key->direction; +} + typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t; /** @@ -262,9 +311,9 @@ struct private_kernel_netlink_ipsec_t { mutex_t *mutex; /** - * List of installed policies (policy_entry_t) + * Hash table of installed policies (policy_entry_t) */ - linked_list_t *policies; + hashtable_t *policies; /** * job receiving netlink events @@ -418,51 +467,48 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src, */ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src) { - int family; - chunk_t addr; + u_char *addr; u_int8_t prefixlen; - u_int16_t port, port_mask; - host_t *host; - traffic_selector_t *ts; - + u_int16_t port = 0; + host_t *host = NULL; + if (src) { - addr.ptr = (u_char*)&sel->saddr; + addr = (u_char*)&sel->saddr; prefixlen = sel->prefixlen_s; - port = sel->sport; - port_mask = sel->sport_mask; + if (sel->sport_mask) + { + port = htons(sel->sport); + } } - else + else { - addr.ptr = (u_char*)&sel->daddr; + addr = (u_char*)&sel->daddr; prefixlen = sel->prefixlen_d; - port = sel->dport; - port_mask = sel->dport_mask; + if (sel->dport_mask) + { + port = htons(sel->dport); + } } - + /* The Linux 2.6 kernel does not set the selector's family field, - * so as a kludge we additionally test the prefix length. + * so as a kludge we additionally test the prefix length. */ if (sel->family == AF_INET || sel->prefixlen_s == 32) { - family = AF_INET; - addr.len = 4; + host = host_create_from_chunk(AF_INET, chunk_create(addr, 4), 0); } else if (sel->family == AF_INET6 || sel->prefixlen_s == 128) { - family = AF_INET6; - addr.len = 16; + host = host_create_from_chunk(AF_INET6, chunk_create(addr, 16), 0); } - else + + if (host) { - return NULL; + return traffic_selector_create_from_subnet(host, prefixlen, + sel->proto, port); } - host = host_create_from_chunk(family, addr, 0); - port = (port_mask == 0) ? 0 : ntohs(port); - - ts = traffic_selector_create_from_subnet(host, prefixlen, sel->proto, port); - host->destroy(host); - return ts; + return NULL; } /** @@ -1064,7 +1110,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, * the IPsec checks it marks them "checksum ok" so OA isn't needed. */ rthdr = XFRM_RTA_NEXT(rthdr); } - + if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi)); @@ -1370,7 +1416,7 @@ static status_t update_sa(private_kernel_netlink_ipsec_t *this, rta = XFRM_RTA_NEXT(rta); } - + if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi)); @@ -1394,7 +1440,6 @@ static status_t add_policy(private_kernel_netlink_ipsec_t *this, ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, bool routed) { - iterator_t *iterator; policy_entry_t *current, *policy; bool found = FALSE; netlink_buf_t request; @@ -1409,27 +1454,21 @@ static status_t add_policy(private_kernel_netlink_ipsec_t *this, /* find the policy, which matches EXACTLY */ this->mutex->lock(this->mutex); - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + current = this->policies->get(this->policies, policy); + if (current) { - if (memeq(¤t->sel, &policy->sel, sizeof(struct xfrm_selector)) && - policy->direction == current->direction) - { - /* use existing policy */ - current->refcount++; - DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " - "refcount", src_ts, dst_ts, - policy_dir_names, direction); - free(policy); - policy = current; - found = TRUE; - break; - } + /* use existing policy */ + current->refcount++; + DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " + "refcount", src_ts, dst_ts, + policy_dir_names, direction); + free(policy); + policy = current; + found = TRUE; } - iterator->destroy(iterator); - if (!found) + else { /* apply the new one, if we have no such policy */ - this->policies->insert_last(this->policies, policy); + this->policies->put(this->policies, policy, policy); policy->refcount = 1; } @@ -1657,7 +1696,6 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this, netlink_buf_t request; struct nlmsghdr *hdr; struct xfrm_userpolicy_id *policy_id; - enumerator_t *enumerator; DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts, policy_dir_names, direction); @@ -1669,28 +1707,21 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this, /* find the policy */ this->mutex->lock(this->mutex); - enumerator = this->policies->create_enumerator(this->policies); - while (enumerator->enumerate(enumerator, ¤t)) + current = this->policies->get(this->policies, &policy); + if (current) { - if (memeq(¤t->sel, &policy.sel, sizeof(struct xfrm_selector)) && - policy.direction == current->direction) + to_delete = current; + if (--to_delete->refcount > 0) { - to_delete = current; - if (--to_delete->refcount > 0) - { - /* is used by more SAs, keep in kernel */ - DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); - this->mutex->unlock(this->mutex); - enumerator->destroy(enumerator); - return SUCCESS; - } - /* remove if last reference */ - this->policies->remove_at(this->policies, enumerator); - break; + /* is used by more SAs, keep in kernel */ + DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); + this->mutex->unlock(this->mutex); + return SUCCESS; } + /* remove if last reference */ + this->policies->remove(this->policies, to_delete); } this->mutex->unlock(this->mutex); - enumerator->destroy(enumerator); if (!to_delete) { DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts, @@ -1739,9 +1770,18 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this, */ static void destroy(private_kernel_netlink_ipsec_t *this) { + enumerator_t *enumerator; + policy_entry_t *policy; + this->job->cancel(this->job); close(this->socket_xfrm_events); this->socket_xfrm->destroy(this->socket_xfrm); + enumerator = this->policies->create_enumerator(this->policies); + while (enumerator->enumerate(enumerator, &policy, &policy)) + { + free(policy); + } + enumerator->destroy(enumerator); this->policies->destroy(this->policies); this->mutex->destroy(this->mutex); free(this); @@ -1832,7 +1872,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() this->public.interface.destroy = (void(*)(kernel_ipsec_t*)) destroy; /* private members */ - this->policies = linked_list_create(); + this->policies = hashtable_create((hashtable_hash_t)policy_hash, + (hashtable_equals_t)policy_equals, 32); this->mutex = mutex_create(MUTEX_DEFAULT); this->install_routes = lib->settings->get_bool(lib->settings, "charon.install_routes", TRUE); diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_net.c b/src/charon/plugins/kernel_netlink/kernel_netlink_net.c index 69a781c14..6e4ddffe5 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_net.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: kernel_netlink_net.c 4660 2008-11-14 14:23:11Z martin $ + * $Id: kernel_netlink_net.c 4671 2008-11-18 09:52:28Z martin $ */ #include <sys/socket.h> @@ -707,7 +707,8 @@ static bool is_interface_up(private_kernel_netlink_net_t *this, int index) { enumerator_t *ifaces; iface_entry_t *iface; - bool up = FALSE; + /* default to TRUE for interface we do not monitor (e.g. lo) */ + bool up = TRUE; ifaces = this->ifaces->create_enumerator(this->ifaces); while (ifaces->enumerate(ifaces, &iface)) diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_shared.c b/src/charon/plugins/kernel_netlink/kernel_netlink_shared.c index 3de56bf48..05bd4e397 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_shared.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_shared.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: kernel_netlink_shared.c 4579 2008-11-05 11:29:56Z martin $ + * $Id: kernel_netlink_shared.c 4831 2009-01-09 09:37:13Z andreas $ */ #include <sys/socket.h> @@ -46,7 +46,12 @@ struct private_netlink_socket_t { * current sequence number for netlink request */ int seq; - + + /** + * netlink socket protocol + */ + int protocol; + /** * netlink socket */ @@ -54,6 +59,11 @@ struct private_netlink_socket_t { }; /** + * Imported from kernel_netlink_ipsec.c + */ +extern enum_name_t *xfrm_msg_names; + +/** * Implementation of netlink_socket_t.send */ static status_t netlink_send(private_netlink_socket_t *this, struct nlmsghdr *in, @@ -74,6 +84,13 @@ static status_t netlink_send(private_netlink_socket_t *this, struct nlmsghdr *in addr.nl_pid = 0; addr.nl_groups = 0; + if (this->protocol == NETLINK_XFRM) + { + chunk_t in_chunk = { (u_char*)in, in->nlmsg_len }; + + DBG3(DBG_KNL, "sending %N: %B", xfrm_msg_names, in->nlmsg_type, &in_chunk); + } + while (TRUE) { len = sendto(this->socket, in, in->nlmsg_len, 0, @@ -245,6 +262,7 @@ netlink_socket_t *netlink_socket_create(int protocol) { memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; + this->protocol = protocol; this->socket = socket(AF_NETLINK, SOCK_RAW, protocol); if (this->socket <= 0) { |
