fully implemented the parsing of XFRM and PF_KEY MIGRATE messages
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user