From 7f57c4f9fbf3bdd559af054795bdbf2dfaa9b810 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Thu, 24 Mar 2016 18:35:27 +0100 Subject: [PATCH] Support manually-set IPsec policy priorities --- src/libcharon/config/child_cfg.c | 15 ++++++ src/libcharon/config/child_cfg.h | 10 ++++ src/libcharon/kernel/kernel_ipsec.h | 3 ++ .../plugins/kernel_netlink/kernel_netlink_ipsec.c | 6 ++- src/libcharon/plugins/vici/vici_config.c | 2 + src/libcharon/sa/child_sa.c | 59 +++++++++++++++------- src/libcharon/sa/shunt_manager.c | 4 +- src/swanctl/swanctl.opt | 7 +++ 8 files changed, 84 insertions(+), 22 deletions(-) diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 1a84d30..a7ec167 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -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(), diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 4eecbf1..8ac9c30 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -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 */ diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index a823814..3a06ce6 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -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 */ diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index b147590..bad343e 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -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)) { diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index e3fd9e9..8358336 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -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, diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 05d42ba..a1e47a2 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -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); diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index 36af86b..b74b454 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -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, diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index d69daea..08d3cf1 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -684,6 +684,13 @@ connections..children..reqid = 0 not more than once. The default of _0_ uses dynamic reqids, allocated incrementally. +connections..children..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..children..mark_in = 0/0x00000000 Netfilter mark and mask for input traffic. -- 2.7.4