Support manually-set IPsec policy priorities
authorAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 24 Mar 2016 17:35:27 +0000 (18:35 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 9 Apr 2016 14:51:01 +0000 (16:51 +0200)
src/libcharon/config/child_cfg.c
src/libcharon/config/child_cfg.h
src/libcharon/kernel/kernel_ipsec.h
src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/libcharon/plugins/vici/vici_config.c
src/libcharon/sa/child_sa.c
src/libcharon/sa/shunt_manager.c
src/swanctl/swanctl.opt

index 1a84d30..a7ec167 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2016 Andreas Steffen
  * Copyright (C) 2008-2016 Tobias Brunner
  * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -133,6 +134,11 @@ struct private_child_cfg_t {
        uint32_t tfc;
 
        /**
+        * Optional manually-set IPsec policy priorities
+        */
+       uint32_t manual_prio;
+
+       /**
         * set up IPsec transport SA in MIPv6 proxy mode
         */
        bool proxy_mode;
@@ -500,6 +506,12 @@ METHOD(child_cfg_t, get_tfc, uint32_t,
        return this->tfc;
 }
 
+METHOD(child_cfg_t, get_manual_prio, uint32_t,
+       private_child_cfg_t *this)
+{
+       return this->manual_prio;
+}
+
 METHOD(child_cfg_t, get_replay_window, uint32_t,
        private_child_cfg_t *this)
 {
@@ -569,6 +581,7 @@ METHOD(child_cfg_t, equals, bool,
                this->mark_out.value == other->mark_out.value &&
                this->mark_out.mask == other->mark_out.mask &&
                this->tfc == other->tfc &&
+               this->manual_prio == other->manual_prio &&
                this->replay_window == other->replay_window &&
                this->proxy_mode == other->proxy_mode &&
                this->install_policy == other->install_policy &&
@@ -627,6 +640,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
                        .get_reqid = _get_reqid,
                        .get_mark = _get_mark,
                        .get_tfc = _get_tfc,
+                       .get_manual_prio = _get_manual_prio,
                        .get_replay_window = _get_replay_window,
                        .set_replay_window = _set_replay_window,
                        .use_proxy_mode = _use_proxy_mode,
@@ -650,6 +664,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
                .inactivity = data->inactivity,
                .use_ipcomp = data->ipcomp,
                .tfc = data->tfc,
+               .manual_prio = data->priority,
                .install_policy = !data->suppress_policies,
                .refcount = 1,
                .proposals = linked_list_create(),
index 4eecbf1..8ac9c30 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2016 Andreas Steffen
  * Copyright (C) 2008-2016 Tobias Brunner
  * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -236,6 +237,13 @@ struct child_cfg_t {
        uint32_t (*get_tfc)(child_cfg_t *this);
 
        /**
+        * Get optional manually-set IPsec policy priority
+        *
+        * @return                              manually-set IPsec policy priority (automatic if 0)
+        */
+       uint32_t (*get_manual_prio)(child_cfg_t *this);
+
+       /**
         * Get anti-replay window size
         *
         * @return                              anti-replay window size
@@ -308,6 +316,8 @@ struct child_cfg_create_t {
        bool ipcomp;
        /** TFC padding size, 0 to disable, -1 to pad to PMTU */
        uint32_t tfc;
+       /** Optional manually-set IPsec policy priority */
+       uint32_t priority;
        /** lifetime_cfg_t for this child_cfg */
        lifetime_cfg_t lifetime;
        /** Inactivity timeout in s before closing a CHILD_SA */
index a823814..3a06ce6 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2016 Andreas Steffen
  * Copyright (C) 2006-2016 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2006 Martin Willi
@@ -151,6 +152,8 @@ struct kernel_ipsec_manage_policy_t {
        policy_type_t type;
        /** Priority class */
        policy_priority_t prio;
+       /** Manually-set priority (automatic if set to 0) */
+       uint32_t manual_prio;
        /** Source address of the SA(s) tied to this policy */
        host_t *src;
        /** Destination address of the SA(s) tied to this policy */
index b147590..bad343e 100644 (file)
@@ -2397,7 +2397,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        /* cache the assigned IPsec SA */
        assigned_sa = policy_sa_create(this, id->dir, data->type, data->src,
                                                data->dst, id->src_ts, id->dst_ts, id->mark, data->sa);
-       assigned_sa->priority = get_priority(policy, data->prio);
+       assigned_sa->priority = data->manual_prio ? data->manual_prio :
+                                                                                               get_priority(policy, data->prio);
 
        /* insert the SA according to its priority */
        enumerator = policy->used_by->create_enumerator(policy->used_by);
@@ -2576,7 +2577,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        }
 
        /* remove mapping to SA by reqid and priority */
-       priority = get_priority(current, data->prio);
+       priority = data->manual_prio ? data->manual_prio :
+                                                                  get_priority(current, data->prio);
        enumerator = current->used_by->create_enumerator(current->used_by);
        while (enumerator->enumerate(enumerator, (void**)&mapping))
        {
index e3fd9e9..8358336 100644 (file)
@@ -461,6 +461,7 @@ static void log_child_data(child_data_t *data, char *name)
        DBG2(DBG_CFG, "   close_action = %N", action_names, cfg->close_action);
        DBG2(DBG_CFG, "   reqid = %u", cfg->reqid);
        DBG2(DBG_CFG, "   tfc = %d", cfg->tfc);
+       DBG2(DBG_CFG, "   priority = %d", cfg->priority);
        DBG2(DBG_CFG, "   mark_in = %u/%u",
                 cfg->mark_in.value, cfg->mark_in.mask);
        DBG2(DBG_CFG, "   mark_out = %u/%u",
@@ -1340,6 +1341,7 @@ CALLBACK(child_kv, bool,
                { "mark_in",            parse_mark,                     &child->cfg.mark_in                                     },
                { "mark_out",           parse_mark,                     &child->cfg.mark_out                            },
                { "tfc_padding",        parse_tfc,                      &child->cfg.tfc                                         },
+               { "priority",           parse_uint32,           &child->cfg.priority                            },
        };
 
        return parse_rules(rules, countof(rules), name, value,
index 05d42ba..a1e47a2 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Coypright (C) 2016 Andreas Steffen
  * Copyright (C) 2006-2016 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2006 Daniel Roethlisberger
@@ -881,7 +882,8 @@ static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa,
 static status_t install_policies_internal(private_child_sa_t *this,
        host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
        traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
-       ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority)
+       ipsec_sa_cfg_t *other_sa, policy_type_t type,
+       policy_priority_t priority,     uint32_t manual_prio)
 {
        kernel_ipsec_policy_id_t out_id = {
                .dir = POLICY_OUT,
@@ -897,12 +899,14 @@ static status_t install_policies_internal(private_child_sa_t *this,
        kernel_ipsec_manage_policy_t out_policy = {
                .type = type,
                .prio = priority,
+               .manual_prio = manual_prio,
                .src = my_addr,
                .dst = other_addr,
                .sa = other_sa,
        }, in_policy = {
                .type = type,
                .prio = priority,
+               .manual_prio = manual_prio,
                .src = other_addr,
                .dst = my_addr,
                .sa = my_sa,
@@ -936,7 +940,8 @@ static status_t install_policies_internal(private_child_sa_t *this,
 static void del_policies_internal(private_child_sa_t *this,
        host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
        traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
-       ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority)
+       ipsec_sa_cfg_t *other_sa, policy_type_t type,
+       policy_priority_t priority, uint32_t manual_prio)
 {
        kernel_ipsec_policy_id_t out_id = {
                .dir = POLICY_OUT,
@@ -952,12 +957,14 @@ static void del_policies_internal(private_child_sa_t *this,
        kernel_ipsec_manage_policy_t out_policy = {
                .type = type,
                .prio = priority,
+               .manual_prio = manual_prio,
                .src = my_addr,
                .dst = other_addr,
                .sa = other_sa,
        }, in_policy = {
                .type = type,
                .prio = priority,
+               .manual_prio = manual_prio,
                .src = other_addr,
                .dst = my_addr,
                .sa = my_sa,
@@ -1019,8 +1026,10 @@ METHOD(child_sa_t, add_policies, status_t,
        {
                policy_priority_t priority;
                ipsec_sa_cfg_t my_sa, other_sa;
+               uint32_t manual_prio;
 
                prepare_sa_cfg(this, &my_sa, &other_sa);
+               manual_prio = this->config->get_manual_prio(this->config);
 
                /* if we're not in state CHILD_INSTALLING (i.e. if there is no SAD
                 * entry) we install a trap policy */
@@ -1034,18 +1043,20 @@ METHOD(child_sa_t, add_policies, status_t,
                {
                        /* install outbound drop policy to avoid packets leaving unencrypted
                         * when updating policies */
-                       if (priority == POLICY_PRIORITY_DEFAULT && require_policy_update())
+                       if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 &&
+                               require_policy_update())
                        {
                                status |= install_policies_internal(this, this->my_addr,
                                                                        this->other_addr, my_ts, other_ts,
                                                                        &my_sa, &other_sa, POLICY_DROP,
-                                                                       POLICY_PRIORITY_FALLBACK);
+                                                                       POLICY_PRIORITY_FALLBACK, 0);
                        }
 
                        /* install policies */
                        status |= install_policies_internal(this, this->my_addr,
                                                                        this->other_addr, my_ts, other_ts,
-                                                                       &my_sa, &other_sa, POLICY_IPSEC, priority);
+                                                                       &my_sa, &other_sa, POLICY_IPSEC,
+                                                                       priority, manual_prio);
 
                        if (status != SUCCESS)
                        {
@@ -1157,18 +1168,21 @@ METHOD(child_sa_t, update, status_t,
                        ipsec_sa_cfg_t my_sa, other_sa;
                        enumerator_t *enumerator;
                        traffic_selector_t *my_ts, *other_ts;
+                       uint32_t manual_prio;
 
                        prepare_sa_cfg(this, &my_sa, &other_sa);
+                       manual_prio = this->config->get_manual_prio(this->config);
 
                        /* always use high priorities, as hosts getting updated are INSTALLED */
                        enumerator = create_policy_enumerator(this);
                        while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
                        {
                                traffic_selector_t *old_my_ts = NULL, *old_other_ts = NULL;
+
                                /* remove old policies first */
                                del_policies_internal(this, this->my_addr, this->other_addr,
-                                                                         my_ts, other_ts, &my_sa, &other_sa,
-                                                                         POLICY_IPSEC, POLICY_PRIORITY_DEFAULT);
+                                                       my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC,
+                                                       POLICY_PRIORITY_DEFAULT, manual_prio);
 
                                /* check if we have to update a "dynamic" traffic selector */
                                if (!me->ip_equals(me, this->my_addr) &&
@@ -1191,17 +1205,20 @@ METHOD(child_sa_t, update, status_t,
                                /* reinstall updated policies */
                                install_policies_internal(this, me, other, my_ts, other_ts,
                                                                                  &my_sa, &other_sa, POLICY_IPSEC,
-                                                                                 POLICY_PRIORITY_DEFAULT);
+                                                                                 POLICY_PRIORITY_DEFAULT, manual_prio);
 
                                /* update fallback policies after the new policy is in place */
-                               del_policies_internal(this, this->my_addr, this->other_addr,
-                                                                         old_my_ts ?: my_ts,
-                                                                         old_other_ts ?: other_ts,
-                                                                         &my_sa, &other_sa, POLICY_DROP,
-                                                                         POLICY_PRIORITY_FALLBACK);
-                               install_policies_internal(this, me, other, my_ts, other_ts,
+                               if (manual_prio == 0)
+                               {
+                                       del_policies_internal(this, this->my_addr, this->other_addr,
+                                                                                 old_my_ts ?: my_ts,
+                                                                                 old_other_ts ?: other_ts,
+                                                                                 &my_sa, &other_sa, POLICY_DROP,
+                                                                                 POLICY_PRIORITY_FALLBACK, 0);
+                                       install_policies_internal(this, me, other, my_ts, other_ts,
                                                                                  &my_sa, &other_sa, POLICY_DROP,
-                                                                                 POLICY_PRIORITY_FALLBACK);
+                                                                                 POLICY_PRIORITY_FALLBACK, 0);
+                               }
                                DESTROY_IF(old_my_ts);
                                DESTROY_IF(old_other_ts);
                        }
@@ -1244,20 +1261,24 @@ METHOD(child_sa_t, destroy, void,
        if (this->config->install_policy(this->config))
        {
                ipsec_sa_cfg_t my_sa, other_sa;
+               uint32_t manual_prio;
 
                prepare_sa_cfg(this, &my_sa, &other_sa);
+               manual_prio = this->config->get_manual_prio(this->config);
 
                /* delete all policies in the kernel */
                enumerator = create_policy_enumerator(this);
                while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
                {
                        del_policies_internal(this, this->my_addr, this->other_addr,
-                                       my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC, priority);
-                       if (priority == POLICY_PRIORITY_DEFAULT && require_policy_update())
+                                                                 my_ts, other_ts, &my_sa, &other_sa,
+                                                                 POLICY_IPSEC, priority, manual_prio);
+                       if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 &&
+                               require_policy_update())
                        {
                                del_policies_internal(this, this->my_addr, this->other_addr,
-                                                               my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP,
-                                                               POLICY_PRIORITY_FALLBACK);
+                                                                         my_ts, other_ts, &my_sa, &other_sa,
+                                                                         POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0);
                        }
                }
                enumerator->destroy(enumerator);
index 36af86b..b74b454 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2015-2016 Tobias Brunner
- * Copyright (C) 2011 Andreas Steffen
+ * Copyright (C) 2011-2016 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -119,6 +119,7 @@ static bool install_shunt_policy(child_cfg_t *child)
                        kernel_ipsec_manage_policy_t policy = {
                                .type = policy_type,
                                .prio = policy_prio,
+                               .manual_prio = child->get_manual_prio(child),
                                .src = host_any,
                                .dst = host_any,
                                .sa = &sa,
@@ -265,6 +266,7 @@ static void uninstall_shunt_policy(child_cfg_t *child)
                        kernel_ipsec_manage_policy_t policy = {
                                .type = policy_type,
                                .prio = policy_prio,
+                               .manual_prio = child->get_manual_prio(child),
                                .src = host_any,
                                .dst = host_any,
                                .sa = &sa,
index d69daea..08d3cf1 100644 (file)
@@ -684,6 +684,13 @@ connections.<conn>.children.<child>.reqid = 0
        not more than once. The default of _0_ uses dynamic reqids, allocated
        incrementally.
 
+connections.<conn>.children.<child>.priority = 0
+       Optional fixed priority for IPsec policies.
+
+       Optional fixed priority for IPsec policies. This could be useful to install
+       high-priority drop policies.  The default of _0_ uses dynamically calculated
+       priorities based on the size of the traffic selectors.
+
 connections.<conn>.children.<child>.mark_in = 0/0x00000000
        Netfilter mark and mask for input traffic.