added non-standard SERPENT and TWOFISH support to kernel_netlink plugin
[strongswan.git] / src / libhydra / plugins / kernel_netlink / kernel_netlink_ipsec.c
index 6ecfa03..8cc9a62 100644 (file)
@@ -183,6 +183,8 @@ static kernel_algorithm_t encryption_algs[] = {
 /*     {ENCR_CAMELLIA_CCM_ICV8,        "***"                           }, */
 /*     {ENCR_CAMELLIA_CCM_ICV12,       "***"                           }, */
 /*     {ENCR_CAMELLIA_CCM_ICV16,       "***"                           }, */
+       {ENCR_SERPENT_CBC,                      "serpent"                       },
+       {ENCR_TWOFISH_CBC,                      "twofish"                       },
        {END_OF_LIST,                           NULL                            }
 };
 
@@ -865,7 +867,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
        lifetime_cfg_t *lifetime, 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,
+       u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
        u_int16_t cpi, bool encap, bool inbound,
        traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
 {
@@ -1021,7 +1023,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                }
        }
 
-       if (int_alg  != AUTH_UNDEFINED)
+       if (int_alg != AUTH_UNDEFINED)
        {
                alg_name = lookup_algorithm(integrity_algs, int_alg);
                if (alg_name == NULL)
@@ -1617,15 +1619,15 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 METHOD(kernel_ipsec_t, add_policy, status_t,
        private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
        traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
-       policy_dir_t direction, u_int32_t spi, u_int8_t protocol,
-       u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
-       u_int16_t cpi, bool routed)
+       policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
+       mark_t mark, bool routed)
 {
        policy_entry_t *current, *policy;
        bool found = FALSE;
        netlink_buf_t request;
        struct xfrm_userpolicy_info *policy_info;
        struct nlmsghdr *hdr;
+       int i;
 
        /* create a policy */
        policy = malloc_thing(policy_entry_t);
@@ -1690,7 +1692,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        policy_info->priority -= policy->sel.prefixlen_s * 10;
        policy_info->priority -= policy->sel.proto ? 2 : 0;
        policy_info->priority -= policy->sel.sport_mask ? 1 : 0;
-       policy_info->action = XFRM_POLICY_ALLOW;
+       policy_info->action = type != POLICY_DROP ? XFRM_POLICY_ALLOW
+                                                                                         : XFRM_POLICY_BLOCK;
        policy_info->share = XFRM_SHARE_ANY;
        this->mutex->unlock(this->mutex);
 
@@ -1705,55 +1708,59 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        policy_info->lft.hard_use_expires_seconds = 0;
 
        struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info);
-       rthdr->rta_type = XFRMA_TMPL;
-       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
 
-       hdr->nlmsg_len += rthdr->rta_len;
-       if (hdr->nlmsg_len > sizeof(request))
+       if (type == POLICY_IPSEC)
        {
-               return FAILED;
-       }
+               struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
+               struct {
+                       u_int8_t proto;
+                       bool use;
+               } protos[] = {
+                       { IPPROTO_COMP, sa->ipcomp.transform != IPCOMP_NONE },
+                       { IPPROTO_ESP, sa->esp.use },
+                       { IPPROTO_AH, sa->ah.use },
+               };
+               ipsec_mode_t proto_mode = sa->mode;
 
-       struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
+               rthdr->rta_type = XFRMA_TMPL;
+               rthdr->rta_len = 0; /* actual length is set below */
 
-       if (ipcomp != IPCOMP_NONE)
-       {
-               tmpl->reqid = reqid;
-               tmpl->id.proto = IPPROTO_COMP;
-               tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
-               tmpl->mode = mode2kernel(mode);
-               tmpl->optional = direction != POLICY_OUT;
-               tmpl->family = src->get_family(src);
+               for (i = 0; i < countof(protos); i++)
+               {
+                       if (!protos[i].use)
+                       {
+                               continue;
+                       }
 
-               host2xfrm(src, &tmpl->saddr);
-               host2xfrm(dst, &tmpl->id.daddr);
+                       rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
+                       hdr->nlmsg_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
+                       if (hdr->nlmsg_len > sizeof(request))
+                       {
+                               return FAILED;
+                       }
 
-               /* add an additional xfrm_user_tmpl */
-               rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
-               hdr->nlmsg_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
+                       tmpl->reqid = sa->reqid;
+                       tmpl->id.proto = protos[i].proto;
+                       tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
+                       tmpl->mode = mode2kernel(proto_mode);
+                       tmpl->optional = protos[i].proto == IPPROTO_COMP &&
+                                                        direction != POLICY_OUT;
+                       tmpl->family = src->get_family(src);
+
+                       if (proto_mode == MODE_TUNNEL)
+                       {       /* only for tunnel mode */
+                               host2xfrm(src, &tmpl->saddr);
+                               host2xfrm(dst, &tmpl->id.daddr);
+                       }
 
-               tmpl++;
+                       tmpl++;
 
-               /* use transport mode for ESP if we have a tunnel mode IPcomp SA */
-               mode = MODE_TRANSPORT;
-       }
-       else
-       {
-               /* when using IPcomp, only the IPcomp SA uses tmp src/dst addresses */
-               host2xfrm(src, &tmpl->saddr);
-               host2xfrm(dst, &tmpl->id.daddr);
-       }
+                       /* use transport mode for other SAs */
+                       proto_mode = MODE_TRANSPORT;
+               }
 
-       tmpl->reqid = reqid;
-       tmpl->id.proto = protocol;
-       tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
-       tmpl->mode = mode2kernel(mode);
-       tmpl->family = src->get_family(src);
-       rthdr = XFRM_RTA_NEXT(rthdr);
+               rthdr = XFRM_RTA_NEXT(rthdr);
+       }
 
        if (mark.value)
        {
@@ -1787,7 +1794,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
         * - routing is not disabled via strongswan.conf
         */
        if (policy->route == NULL && direction == POLICY_FWD &&
-               mode != MODE_TRANSPORT && this->install_routes)
+               sa->mode != MODE_TRANSPORT && this->install_routes)
        {
                route_entry_t *route = malloc_thing(route_entry_t);
 
@@ -1943,7 +1950,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
 
 METHOD(kernel_ipsec_t, del_policy, status_t,
        private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
-       traffic_selector_t *dst_ts, policy_dir_t direction,     mark_t mark,
+       traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
        bool unrouted)
 {
        policy_entry_t *current, policy, *to_delete = NULL;
@@ -2162,9 +2169,15 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
                                                                         (hashtable_equals_t)policy_equals, 32),
                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                .install_routes = lib->settings->get_bool(lib->settings,
-                                                                                               "charon.install_routes", TRUE),
+                                                                                                 "%s.install_routes", TRUE,
+                                                                                                 hydra->daemon),
        );
 
+       if (streq(hydra->daemon, "pluto"))
+       {       /* no routes for pluto, they are installed via updown script */
+               this->install_routes = FALSE;
+       }
+
        /* disable lifetimes for allocated SPIs in kernel */
        fd = open("/proc/sys/net/core/xfrm_acq_expires", O_WRONLY);
        if (fd)