fully implemented the parsing of XFRM and PF_KEY MIGRATE messages
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 2 Nov 2008 21:34:52 +0000 (21:34 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 2 Nov 2008 21:34:52 +0000 (21:34 -0000)
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c

index c454f31..fc7f78a 100644 (file)
@@ -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);
 }
 
 /**
index cb4d006..487be57 100644 (file)
@@ -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);
 }
 
 /**