From 5145ae48be4c493ec886ddc7c4a385d95c6957d2 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Sun, 2 Nov 2008 21:34:52 +0000 Subject: [PATCH] fully implemented the parsing of XFRM and PF_KEY MIGRATE messages --- .../kernel_netlink/kernel_netlink_ipsec.c | 79 ++++++++++++++----- .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 51 +++++++----- 2 files changed, 94 insertions(+), 36 deletions(-) diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c index c454f3127..fc7f78aee 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -409,19 +409,24 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src, */ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src) { - ts_type_t type; + int family; chunk_t addr; - u_int16_t port, port_mask, from_port, to_port; + u_int8_t prefixlen; + u_int16_t port, port_mask; + host_t *host; + traffic_selector_t *ts; if (src) { addr.ptr = (u_char*)&sel->saddr; + prefixlen = sel->prefixlen_s; port = sel->sport; port_mask = sel->sport_mask; } else { addr.ptr = (u_char*)&sel->daddr; + prefixlen = sel->prefixlen_d; port = sel->dport; port_mask = sel->dport_mask; } @@ -431,31 +436,24 @@ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src) */ if (sel->family == AF_INET || sel->prefixlen_s == 32) { - type = TS_IPV4_ADDR_RANGE; + family = AF_INET; addr.len = 4; } else if (sel->family == AF_INET6 || sel->prefixlen_s == 128) { - type = TS_IPV6_ADDR_RANGE; + family = AF_INET6; addr.len = 16; } else { return NULL; } - - if (port_mask == 0) - { - from_port = 0; - to_port = 65535; - } - else - { - from_port = to_port = ntohs(port); - } - - return traffic_selector_create_from_bytes(sel->proto, type, - addr, from_port, addr, to_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; } /** @@ -552,19 +550,64 @@ static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr */ static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr) { + traffic_selector_t *src_ts, *dst_ts; + host_t *local = NULL, *remote = NULL; + host_t *old_src = NULL, *old_dst = NULL; + host_t *new_src = NULL, *new_dst = NULL; + struct xfrm_userpolicy_id *policy_id; struct rtattr *rta; size_t rtasize; + u_int32_t reqid = 0; + job_t *job; + policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr); rta = XFRM_RTA(hdr, struct xfrm_userpolicy_id); rtasize = XFRM_PAYLOAD(hdr, struct xfrm_userpolicy_id); DBG2(DBG_KNL, "received a XFRM_MSG_MIGRATE"); + + src_ts = selector2ts(&policy_id->sel, TRUE); + dst_ts = selector2ts(&policy_id->sel, FALSE); + DBG2(DBG_KNL, " policy: %R === %R %N, index %u", src_ts, dst_ts, + policy_dir_names, policy_id->dir, policy_id->index); while (RTA_OK(rta, rtasize)) { - DBG2(DBG_KNL, " %N", xfrm_attr_type_names, rta->rta_type); + DBG2(DBG_KNL, " %N", xfrm_attr_type_names, rta->rta_type); + if (rta->rta_type == XFRMA_KMADDRESS) + { + struct xfrm_user_kmaddress *kmaddress; + + kmaddress = (struct xfrm_user_kmaddress*)RTA_DATA(rta); + local = xfrm2host(kmaddress->family, &kmaddress->local, 0); + remote = xfrm2host(kmaddress->family, &kmaddress->remote, 0); + DBG2(DBG_KNL, " %H...%H", local, remote); + DESTROY_IF(remote); } + else if (rta->rta_type == XFRMA_MIGRATE) + { + struct xfrm_user_migrate *migrate; + protocol_id_t proto; + + migrate = (struct xfrm_user_migrate*)RTA_DATA(rta); + old_src = xfrm2host(migrate->old_family, &migrate->old_saddr, 0); + old_dst = xfrm2host(migrate->old_family, &migrate->old_daddr, 0); + new_src = xfrm2host(migrate->new_family, &migrate->new_saddr, 0); + new_dst = xfrm2host(migrate->new_family, &migrate->new_daddr, 0); + proto = proto_kernel2ike(migrate->proto); + reqid = migrate->reqid; + DBG2(DBG_KNL, " migrate %N %H...%H to %H...%H, reqid {%u}", + protocol_id_names, proto, old_src, old_dst, + new_src, new_src, reqid); + DESTROY_IF(old_src); + DESTROY_IF(old_dst); + DESTROY_IF(new_src); + DESTROY_IF(new_dst); + } rta = RTA_NEXT(rta, rtasize); } + DESTROY_IF(src_ts); + DESTROY_IF(dst_ts); + DESTROY_IF(local); } /** diff --git a/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index cb4d006ca..487be57f1 100644 --- a/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -411,6 +411,23 @@ static u_int8_t dir2kernel(policy_dir_t dir) } } +/** + * convert the policy direction in ipsec.h to the general one. + */ +static policy_dir_t kernel2dir(u_int8_t dir) +{ + switch (dir) + { + case IPSEC_DIR_INBOUND: + return POLICY_IN; + case IPSEC_DIR_OUTBOUND: + return POLICY_OUT; + case IPSEC_DIR_FWD: + return POLICY_FWD; + default: + return dir; + } +} typedef struct kernel_algorithm_t kernel_algorithm_t; /** @@ -541,30 +558,14 @@ static void add_encap_ext(struct sadb_msg *msg, host_t *src, host_t *dst) static traffic_selector_t* sadb_address2ts(struct sadb_address *address) { traffic_selector_t *ts; - ts_type_t type; - chunk_t addr; host_t *host; - u_int16_t port, from_port, to_port; /* The Linux 2.6 kernel does not set the protocol and port information * in the src and dst sadb_address extensions of the SADB_ACQUIRE message. */ host = host_create_from_sockaddr((sockaddr_t*)&address[1]) ; - type = (host->get_family(host) == AF_INET) ? TS_IPV4_ADDR_RANGE : - TS_IPV6_ADDR_RANGE; - addr = host->get_address(host); - port = host->get_port(host); - if (port == 0) - { - from_port = 0; - to_port = 65535; - } - else - { - from_port = to_port = port; - } - ts = traffic_selector_create_from_bytes(address->sadb_address_proto, type, - addr, from_port, addr, to_port); + ts = traffic_selector_create_from_subnet(host, address->sadb_address_prefixlen, + address->sadb_address_proto, host->get_port(host)); host->destroy(host); return ts; } @@ -833,6 +834,9 @@ static void process_expire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* static void process_migrate(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg) { pfkey_msg_t response; + traffic_selector_t *src_ts, *dst_ts; + policy_dir_t dir; + host_t *local; DBG2(DBG_KNL, "received an SADB_X_MIGRATE"); @@ -841,6 +845,17 @@ static void process_migrate(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* DBG1(DBG_KNL, "parsing SADB_X_MIGRATE from kernel failed"); return; } + src_ts = sadb_address2ts(response.src); + dst_ts = sadb_address2ts(response.dst); + local = host_create_from_sockaddr((sockaddr_t*)&response.x_kmaddress[1]); + dir = kernel2dir(response.x_policy->sadb_x_policy_dir); + DBG2(DBG_KNL, " policy %R === %R %N, id %u", src_ts, dst_ts, + policy_dir_names, dir, response.x_policy->sadb_x_policy_id); + DBG2(DBG_KNL, " kmaddress: %H", local); + + src_ts->destroy(src_ts); + dst_ts->destroy(dst_ts); + local->destroy(local); } /**