parse xfrm and pf_key acquire messages and subscribe to migrate messages
[strongswan.git] / src / charon / plugins / kernel_netlink / kernel_netlink_ipsec.c
index 3fe6823..d5ff479 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2006-2008 Tobias Brunner
- * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005 Jan Hutter
 typedef struct kernel_algorithm_t kernel_algorithm_t;
 
 /**
- * Mapping from the algorithms defined in IKEv2 to
- * kernel level algorithm names and their key length
+ * Mapping of IKEv2 kernel identifier to linux crypto API names
  */
 struct kernel_algorithm_t {
        /**
         * Identifier specified in IKEv2
         */
-       int ikev2_id;
+       int ikev2;
        
        /**
-        * Name of the algorithm, as used as kernel identifier
+        * Name of the algorithm in linux crypto API
         */
        char *name;
-       
-       /**
-        * Key length in bits, if fixed size
-        */
-       u_int key_size;
 };
 
-ENUM(policy_dir_names, POLICY_IN, POLICY_FWD,
-       "in",
-       "out",
-       "fwd"
-);
-
 #define END_OF_LIST -1
 
 /**
  * Algorithms for encryption
  */
 static kernel_algorithm_t encryption_algs[] = {
-/*     {ENCR_DES_IV64,                 "***",                                  0}, */
-       {ENCR_DES,                              "des",                                  64},
-       {ENCR_3DES,                     "des3_ede",                             192},
-/*     {ENCR_RC5,                              "***",                                  0}, */
-/*     {ENCR_IDEA,                     "***",                                  0}, */
-       {ENCR_CAST,                     "cast128",                              0},
-       {ENCR_BLOWFISH,                 "blowfish",                             0},
-/*     {ENCR_3IDEA,                    "***",                                  0}, */
-/*     {ENCR_DES_IV32,                 "***",                                  0}, */
-       {ENCR_NULL,                     "cipher_null",                  0},
-       {ENCR_AES_CBC,                  "aes",                                  0},
-/*     {ENCR_AES_CTR,                  "***",                                  0}, */
-       {ENCR_AES_CCM_ICV8,             "rfc4309(ccm(aes))",    64},    /* key_size = ICV size */
-       {ENCR_AES_CCM_ICV12,    "rfc4309(ccm(aes))",    96},    /* key_size = ICV size */
-       {ENCR_AES_CCM_ICV16,    "rfc4309(ccm(aes))",    128},   /* key_size = ICV size */
-       {ENCR_AES_GCM_ICV8,             "rfc4106(gcm(aes))",    64},    /* key_size = ICV size */
-       {ENCR_AES_GCM_ICV12,    "rfc4106(gcm(aes))",    96},    /* key_size = ICV size */
-       {ENCR_AES_GCM_ICV16,    "rfc4106(gcm(aes))",    128},   /* key_size = ICV size */
-       {END_OF_LIST,           NULL,                   0},
+/*     {ENCR_DES_IV64,                         "***"                           }, */
+       {ENCR_DES,                                      "des"                           },
+       {ENCR_3DES,                             "des3_ede"                      },
+/*     {ENCR_RC5,                                      "***"                           }, */
+/*     {ENCR_IDEA,                             "***"                           }, */
+       {ENCR_CAST,                             "cast128"                       },
+       {ENCR_BLOWFISH,                         "blowfish"                      },
+/*     {ENCR_3IDEA,                            "***"                           }, */
+/*     {ENCR_DES_IV32,                         "***"                           }, */
+       {ENCR_NULL,                             "cipher_null"           },
+       {ENCR_AES_CBC,                          "aes"                           },
+/*     {ENCR_AES_CTR,                          "***"                           }, */
+       {ENCR_AES_CCM_ICV8,                     "rfc4309(ccm(aes))"     },
+       {ENCR_AES_CCM_ICV12,            "rfc4309(ccm(aes))"     },
+       {ENCR_AES_CCM_ICV16,            "rfc4309(ccm(aes))"     },
+       {ENCR_AES_GCM_ICV8,                     "rfc4106(gcm(aes))"     },
+       {ENCR_AES_GCM_ICV12,            "rfc4106(gcm(aes))"     },
+       {ENCR_AES_GCM_ICV16,            "rfc4106(gcm(aes))"     },
+       {END_OF_LIST,                           NULL                            },
 };
 
 /**
  * Algorithms for integrity protection
  */
 static kernel_algorithm_t integrity_algs[] = {
-       {AUTH_HMAC_MD5_96,                      "md5",                  128},
-       {AUTH_HMAC_SHA1_96,                     "sha1",                 160},
-       {AUTH_HMAC_SHA2_256_128,        "sha256",               256},
-       {AUTH_HMAC_SHA2_384_192,        "sha384",               384},
-       {AUTH_HMAC_SHA2_512_256,        "sha512",               512},
-/*     {AUTH_DES_MAC,                          "***",                  0}, */
-/*     {AUTH_KPDK_MD5,                         "***",                  0}, */
-       {AUTH_AES_XCBC_96,                      "xcbc(aes)",    128},
-       {END_OF_LIST,                           NULL,                   0},
+       {AUTH_HMAC_MD5_96,                      "md5"                           },
+       {AUTH_HMAC_SHA1_96,                     "sha1"                          },
+       {AUTH_HMAC_SHA2_256_128,        "sha256"                        },
+       {AUTH_HMAC_SHA2_384_192,        "sha384"                        },
+       {AUTH_HMAC_SHA2_512_256,        "sha512"                        },
+/*     {AUTH_DES_MAC,                          "***"                           }, */
+/*     {AUTH_KPDK_MD5,                         "***"                           }, */
+       {AUTH_AES_XCBC_96,                      "xcbc(aes)"                     },
+       {END_OF_LIST,                           NULL                            },
 };
 
 /**
  * Algorithms for IPComp
  */
 static kernel_algorithm_t compression_algs[] = {
-/*     {IPCOMP_OUI,                    "***",                  0}, */
-       {IPCOMP_DEFLATE,                "deflate",              0},
-       {IPCOMP_LZS,                    "lzs",                  0},
-       {IPCOMP_LZJH,                   "lzjh",                 0},
-       {END_OF_LIST,                   NULL,                   0},
+/*     {IPCOMP_OUI,                            "***"                           }, */
+       {IPCOMP_DEFLATE,                        "deflate"                       },
+       {IPCOMP_LZS,                            "lzs"                           },
+       {IPCOMP_LZJH,                           "lzjh"                          },
+       {END_OF_LIST,                           NULL                            },
 };
 
 /**
  * Look up a kernel algorithm name and its key size
  */
-static char* lookup_algorithm(kernel_algorithm_t *kernel_algo, 
-                                          u_int16_t ikev2_algo, u_int16_t *key_size)
+static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2)
 {
-       while (kernel_algo->ikev2_id != END_OF_LIST)
+       while (list->ikev2 != END_OF_LIST)
        {
-               if (ikev2_algo == kernel_algo->ikev2_id)
+               if (list->ikev2 == ikev2)
                {
-                       /* match, evaluate key length */
-                       if (key_size && *key_size == 0)
-                       {       /* update key size if not set */
-                               *key_size = kernel_algo->key_size;
-                       }
-                       return kernel_algo->name;
+                       return list->name;
                }
-               kernel_algo++;
+               list++;
        }
        return NULL;
 }
@@ -221,9 +203,6 @@ struct policy_entry_t {
        /** direction of this policy: in, out, forward */
        u_int8_t direction;
        
-       /** reqid of the policy */
-       u_int32_t reqid;
-       
        /** parameters of installed policy */
        struct xfrm_selector sel;
        
@@ -344,41 +323,13 @@ static host_t* xfrm2host(int family, xfrm_address_t *xfrm, u_int16_t port)
 static void ts2subnet(traffic_selector_t* ts, 
                                          xfrm_address_t *net, u_int8_t *mask)
 {
-       /* there is no way to do this cleanly, as the address range may
-        * be anything else but a subnet. We use from_addr as subnet 
-        * and try to calculate a usable subnet mask.
-        */
-       int byte, bit;
-       bool found = FALSE;
-       chunk_t from, to;
-       size_t size = (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+       host_t *net_host;
+       chunk_t net_chunk;
        
-       from = ts->get_from_address(ts);
-       to = ts->get_to_address(ts);
-       
-       *mask = (size * 8);
-       /* go trough all bits of the addresses, beginning in the front.
-        * as long as they are equal, the subnet gets larger
-        */
-       for (byte = 0; byte < size; byte++)
-       {
-               for (bit = 7; bit >= 0; bit--)
-               {
-                       if ((1<<bit & from.ptr[byte]) != (1<<bit & to.ptr[byte]))
-                       {
-                               *mask = ((7 - bit) + (byte * 8));
-                               found = TRUE;
-                               break;
-                       }
-               }
-               if (found)
-               {
-                       break;
-               }
-       }
-       memcpy(net, from.ptr, from.len);
-       chunk_free(&from);
-       chunk_free(&to);
+       ts->to_subnet(ts, &net_host, mask);
+       net_chunk = net_host->get_address(net_host);
+       memcpy(net, net_chunk.ptr, net_chunk.len);
+       net_host->destroy(net_host);
 }
 
 /**
@@ -430,6 +381,53 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src,
        return sel;
 }
 
+/**
+ * convert a xfrm_selector to a src|dst traffic_selector 
+ */
+static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
+{
+       ts_type_t type;
+       chunk_t addr;
+       u_int16_t port, port_mask, from_port, to_port;
+
+       if (src)
+       {
+               addr.ptr = (u_char*)&sel->saddr;
+               port = sel->sport;
+               port_mask = sel->sport_mask;
+       }
+    else
+       {
+               addr.ptr = (u_char*)&sel->daddr;
+               port = sel->dport;
+               port_mask = sel->dport_mask;
+       }
+       /* The Linux 2.6 kernel does not set the selector's family field,
+     * so as a kludge we additionally test the prefix length. 
+        */
+       if (sel->family == AF_INET || sel->prefixlen_d == 32)
+       {
+               type = TS_IPV4_ADDR_RANGE;
+               addr.len = 4;
+       }
+       else
+       {
+               type = TS_IPV6_ADDR_RANGE;
+               addr.len = 16;
+       } 
+       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);
+}
 
 /**
  * process a XFRM_MSG_ACQUIRE from kernel
@@ -438,15 +436,22 @@ static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghd
 {
        u_int32_t reqid = 0;
        int proto = 0;
+       traffic_selector_t *src_ts, *dst_ts;
+       struct xfrm_user_acquire *acquire;
+       struct rtattr *rtattr;
+       size_t rtsize;
        job_t *job;
-       struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire);
-       size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
        
+       rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire);
+       rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
+
        if (RTA_OK(rtattr, rtsize))
        {
                if (rtattr->rta_type == XFRMA_TMPL)
                {
-                       struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr);
+                       struct xfrm_user_tmpl* tmpl;
+
+                       tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr);
                        reqid = tmpl->reqid;
                        proto = tmpl->id.proto;
                }
@@ -461,14 +466,14 @@ static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghd
                        /* acquire for AH/ESP only, not for IPCOMP */
                        return;
        }
-       if (reqid == 0)
-       {
-               DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found");
-               return;
-       }
        DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE");
-       DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid {%d}", reqid);
-       job = (job_t*)acquire_job_create(reqid);
+
+       acquire = (struct xfrm_user_acquire*)NLMSG_DATA(hdr);
+       src_ts = selector2ts(&acquire->sel, TRUE);
+       dst_ts = selector2ts(&acquire->sel, FALSE);
+       DBG1(DBG_KNL, "creating acquire job %R === %R for CHILD_SA with reqid {%d}",
+                                       src_ts, dst_ts, reqid);
+       job = (job_t*)acquire_job_create(reqid, src_ts, dst_ts);
        charon->processor->queue_job(charon->processor, job);
 }
 
@@ -511,6 +516,14 @@ static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr
 }
 
 /**
+ * process a XFRM_MSG_MIGRATE from kernel
+ */
+static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
+{
+       DBG2(DBG_KNL, "received a XFRM_MSG_MIGRATE");
+}
+
+/**
  * process a XFRM_MSG_MAPPING from kernel
  */
 static void process_mapping(private_kernel_netlink_ipsec_t *this,
@@ -534,7 +547,7 @@ static void process_mapping(private_kernel_netlink_ipsec_t *this,
                if (host)
                {
                        DBG1(DBG_KNL, "NAT mappings of ESP CHILD_SA with SPI %.8x and "
-                               "reqid {%d} changed, queueing update job", ntohl(spi), reqid);
+                               "reqid {%d} changed, queuing update job", ntohl(spi), reqid);
                        job = (job_t*)update_sa_job_create(reqid, host);
                        charon->processor->queue_job(charon->processor, job);
                }
@@ -589,6 +602,9 @@ static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this)
                        case XFRM_MSG_EXPIRE:
                                process_expire(this, hdr);
                                break;
+                       case XFRM_MSG_MIGRATE:
+                               process_migrate(this, hdr);
+                               break;
                        case XFRM_MSG_MAPPING:
                                process_mapping(this, hdr);
                                break;
@@ -601,64 +617,6 @@ static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this)
 }
 
 /**
- * Tries to find an ip address of a local interface that is included in the
- * supplied traffic selector.
- */
-static status_t get_address_by_ts(private_kernel_netlink_ipsec_t *this,
-                                                                 traffic_selector_t *ts, host_t **ip)
-{
-       enumerator_t *addrs;
-       host_t *host;
-       int family;
-       bool found = FALSE;
-       
-       DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
-       
-       /* if we have a family which includes localhost, we do not
-        * search for an IP, we use the default */
-       family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
-       
-       if (family == AF_INET)
-       {
-               host = host_create_from_string("127.0.0.1", 0);
-       }
-       else
-       {
-               host = host_create_from_string("::1", 0);
-       }
-       
-       if (ts->includes(ts, host))
-       {
-               *ip = host_create_any(family);
-               host->destroy(host);
-               DBG2(DBG_KNL, "using host %H", *ip);
-               return SUCCESS;
-       }
-       host->destroy(host);
-       
-       addrs = charon->kernel_interface->create_address_enumerator(
-                               charon->kernel_interface, TRUE, TRUE);
-       while (addrs->enumerate(addrs, (void**)&host))
-       {
-               if (ts->includes(ts, host))
-               {
-                       found = TRUE;
-                       *ip = host->clone(host);
-                       break;
-               }
-       }
-       addrs->destroy(addrs);
-       
-       if (!found)
-       {
-               DBG1(DBG_KNL, "no local address found in traffic selector %R", ts);
-               return FAILED;
-       }
-       DBG2(DBG_KNL, "using host %H", *ip);
-       return SUCCESS;
-}
-
-/**
  * Get an SPI for a specific protocol from the kernel.
  */
 static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this,
@@ -783,23 +741,22 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                                           host_t *src, host_t *dst, u_int32_t spi,
                                           protocol_id_t protocol, u_int32_t reqid,
                                           u_int64_t expire_soft, u_int64_t expire_hard,
-                                          u_int16_t enc_alg, u_int16_t enc_size,
-                                          u_int16_t int_alg, u_int16_t int_size,
-                                          prf_plus_t *prf_plus, ipsec_mode_t mode,
-                                          u_int16_t ipcomp, bool encap,
+                                          u_int16_t enc_alg, chunk_t enc_key,
+                                          u_int16_t int_alg, chunk_t int_key,
+                                          ipsec_mode_t mode, u_int16_t ipcomp, bool encap,
                                           bool replace)
 {
        unsigned char request[NETLINK_BUFFER_SIZE];
        char *alg_name;
-       /* additional 4 octets KEYMAT required for AES-GCM as of RFC4106 8.1. */
-       u_int16_t add_keymat = 32; 
        struct nlmsghdr *hdr;
        struct xfrm_usersa_info *sa;
+       u_int16_t icv_size = 64;        
        
        memset(&request, 0, sizeof(request));
        
-       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}", ntohl(spi), reqid);
-
+       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}",
+                ntohl(spi), reqid);
+       
        hdr = (struct nlmsghdr*)request;
        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        hdr->nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
@@ -836,19 +793,19 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                case ENCR_UNDEFINED:
                        /* no encryption */
                        break;
-               case ENCR_AES_CCM_ICV8:
-               case ENCR_AES_CCM_ICV12:
                case ENCR_AES_CCM_ICV16:
-                       /* AES-CCM needs only 3 additional octets KEYMAT as of RFC 4309 7.1. */
-                       add_keymat = 24;
-                       /* fall-through */
-               case ENCR_AES_GCM_ICV8:
-               case ENCR_AES_GCM_ICV12:
                case ENCR_AES_GCM_ICV16:
+                       icv_size += 32;
+                       /* FALL */
+               case ENCR_AES_CCM_ICV12:
+               case ENCR_AES_GCM_ICV12:
+                       icv_size += 32;
+                       /* FALL */
+               case ENCR_AES_CCM_ICV8:
+               case ENCR_AES_GCM_ICV8:
                {
-                       u_int16_t icv_size = 0;
                        rthdr->rta_type = XFRMA_ALG_AEAD;
-                       alg_name = lookup_algorithm(encryption_algs, enc_alg, &icv_size);
+                       alg_name = lookup_algorithm(encryption_algs, enc_alg);
                        if (alg_name == NULL)
                        {
                                DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
@@ -856,12 +813,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                                return FAILED;
                        }
                        DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
-                                encryption_algorithm_names, enc_alg, enc_size);
+                                encryption_algorithm_names, enc_alg, enc_key.len * 8);
                        
-                       /* additional KEYMAT required */
-                       enc_size += add_keymat;
-                       
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_size / 8);
+                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_key.len);
                        hdr->nlmsg_len += rthdr->rta_len;
                        if (hdr->nlmsg_len > sizeof(request))
                        {
@@ -869,10 +823,10 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                        }
                        
                        struct xfrm_algo_aead* algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr);
-                       algo->alg_key_len = enc_size;
+                       algo->alg_key_len = enc_key.len * 8;
                        algo->alg_icv_len = icv_size;
                        strcpy(algo->alg_name, alg_name);
-                       prf_plus->get_bytes(prf_plus, enc_size / 8, algo->alg_key);
+                       memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
                        
                        rthdr = XFRM_RTA_NEXT(rthdr);
                        break;
@@ -880,7 +834,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                default:
                {
                        rthdr->rta_type = XFRMA_ALG_CRYPT;
-                       alg_name = lookup_algorithm(encryption_algs, enc_alg, &enc_size);
+                       alg_name = lookup_algorithm(encryption_algs, enc_alg);
                        if (alg_name == NULL)
                        {
                                DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
@@ -888,9 +842,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                                return FAILED;
                        }
                        DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
-                                encryption_algorithm_names, enc_alg, enc_size);
+                                encryption_algorithm_names, enc_alg, enc_key.len * 8);
                        
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_size / 8);
+                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len);
                        hdr->nlmsg_len += rthdr->rta_len;
                        if (hdr->nlmsg_len > sizeof(request))
                        {
@@ -898,9 +852,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                        }
                        
                        struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
-                       algo->alg_key_len = enc_size;
+                       algo->alg_key_len = enc_key.len * 8;
                        strcpy(algo->alg_name, alg_name);
-                       prf_plus->get_bytes(prf_plus, enc_size / 8, algo->alg_key);
+                       memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
                        
                        rthdr = XFRM_RTA_NEXT(rthdr);
                        break;
@@ -910,7 +864,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
        if (int_alg  != AUTH_UNDEFINED)
        {
                rthdr->rta_type = XFRMA_ALG_AUTH;
-               alg_name = lookup_algorithm(integrity_algs, int_alg, &int_size);
+               alg_name = lookup_algorithm(integrity_algs, int_alg);
                if (alg_name == NULL)
                {
                        DBG1(DBG_KNL, "algorithm %N not supported by kernel!", 
@@ -918,9 +872,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                        return FAILED;
                }
                DBG2(DBG_KNL, "  using integrity algorithm %N with key size %d",
-                        integrity_algorithm_names, int_alg, int_size);
+                        integrity_algorithm_names, int_alg, int_key.len * 8);
                
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_size / 8);
+               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len);
                hdr->nlmsg_len += rthdr->rta_len;
                if (hdr->nlmsg_len > sizeof(request))
                {
@@ -928,9 +882,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                }
                
                struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
-               algo->alg_key_len = int_size;
+               algo->alg_key_len = int_key.len * 8;
                strcpy(algo->alg_name, alg_name);
-               prf_plus->get_bytes(prf_plus, int_size / 8, algo->alg_key);
+               memcpy(algo->alg_key, int_key.ptr, int_key.len);
                
                rthdr = XFRM_RTA_NEXT(rthdr);
        }
@@ -938,7 +892,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
        if (ipcomp != IPCOMP_NONE)
        {
                rthdr->rta_type = XFRMA_ALG_COMP;
-               alg_name = lookup_algorithm(compression_algs, ipcomp, NULL);
+               alg_name = lookup_algorithm(compression_algs, ipcomp);
                if (alg_name == NULL)
                {
                        DBG1(DBG_KNL, "algorithm %N not supported by kernel!", 
@@ -1257,74 +1211,6 @@ static status_t update_sa(private_kernel_netlink_ipsec_t *this,
 }
 
 /**
- * Implementation of kernel_interface_t.query_sa.
- */
-static status_t query_sa(private_kernel_netlink_ipsec_t *this, host_t *dst,
-                                                u_int32_t spi, protocol_id_t protocol,
-                                                u_int32_t *use_time)
-{
-       unsigned char request[NETLINK_BUFFER_SIZE];
-       struct nlmsghdr *out = NULL, *hdr;
-       struct xfrm_usersa_id *sa_id;
-       struct xfrm_usersa_info *sa = NULL;
-       size_t len;
-       
-       DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi));
-       memset(&request, 0, sizeof(request));
-       
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST;
-       hdr->nlmsg_type = XFRM_MSG_GETSA;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
-
-       sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
-       host2xfrm(dst, &sa_id->daddr);
-       sa_id->spi = spi;
-       sa_id->proto = proto_ike2kernel(protocol);
-       sa_id->family = dst->get_family(dst);
-       
-       if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
-       {
-               hdr = out;
-               while (NLMSG_OK(hdr, len))
-               {
-                       switch (hdr->nlmsg_type)
-                       {
-                               case XFRM_MSG_NEWSA:
-                               {
-                                       sa = NLMSG_DATA(hdr);
-                                       break;
-                               }
-                               case NLMSG_ERROR:
-                               {
-                                       struct nlmsgerr *err = NLMSG_DATA(hdr);
-                                       DBG1(DBG_KNL, "querying SAD entry failed: %s (%d)",
-                                                strerror(-err->error), -err->error);
-                                       break;
-                               }
-                               default:
-                                       hdr = NLMSG_NEXT(hdr, len);
-                                       continue;
-                               case NLMSG_DONE:
-                                       break;
-                       }
-                       break;
-               }
-       }
-       
-       if (sa == NULL)
-       {
-               DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi));
-               free(out);
-               return FAILED;
-       }
-       
-       *use_time = sa->curlft.use_time;
-       free (out);
-       return SUCCESS;
-}
-
-/**
  * Implementation of kernel_interface_t.del_sa.
  */
 static status_t del_sa(private_kernel_netlink_ipsec_t *this, host_t *dst,
@@ -1503,7 +1389,8 @@ static status_t add_policy(private_kernel_netlink_ipsec_t *this,
        {
                route_entry_t *route = malloc_thing(route_entry_t);
                
-               if (get_address_by_ts(this, dst_ts, &route->src_ip) == SUCCESS)
+               if (charon->kernel_interface->get_address_by_ts(charon->kernel_interface,
+                               dst_ts, &route->src_ip) == SUCCESS)
                {
                        /* get the nexthop to src (src as we are in POLICY_FWD).*/
                        route->gateway = charon->kernel_interface->get_nexthop(
@@ -1638,7 +1525,7 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this,
        iterator = this->policies->create_iterator_locked(this->policies, &this->mutex);
        while (iterator->iterate(iterator, (void**)&current))
        {
-               if (memcmp(&current->sel, &policy.sel, sizeof(struct xfrm_selector)) == 0 &&
+               if (memeq(&current->sel, &policy.sel, sizeof(struct xfrm_selector)) &&
                        policy.direction == current->direction)
                {
                        to_delete = current;
@@ -1721,9 +1608,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
        /* public functions */
        this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
        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,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,ipsec_mode_t,u_int16_t,bool,bool))add_sa;
+       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,bool,bool))add_sa;
        this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa;
-       this->public.interface.query_sa = (status_t(*)(kernel_ipsec_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa;
        this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,u_int32_t,protocol_id_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,protocol_id_t,u_int32_t,bool,ipsec_mode_t,u_int16_t))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;