File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libipsec / ipsec_policy_mgr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:44 2020 UTC (4 years, 3 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    1: /*
    2:  * Copyright (C) 2012 Tobias Brunner
    3:  * Copyright (C) 2012 Giuliano Grassi
    4:  * Copyright (C) 2012 Ralf Sager
    5:  * HSR Hochschule fuer Technik Rapperswil
    6:  *
    7:  * This program is free software; you can redistribute it and/or modify it
    8:  * under the terms of the GNU General Public License as published by the
    9:  * Free Software Foundation; either version 2 of the License, or (at your
   10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
   11:  *
   12:  * This program is distributed in the hope that it will be useful, but
   13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   15:  * for more details.
   16:  */
   17: 
   18: #include "ipsec_policy_mgr.h"
   19: 
   20: #include <utils/debug.h>
   21: #include <threading/rwlock.h>
   22: #include <collections/linked_list.h>
   23: 
   24: /** Base priority for installed policies */
   25: #define PRIO_BASE 384
   26: 
   27: typedef struct private_ipsec_policy_mgr_t private_ipsec_policy_mgr_t;
   28: 
   29: /**
   30:  * Private additions to ipsec_policy_mgr_t.
   31:  */
   32: struct private_ipsec_policy_mgr_t {
   33: 
   34: 	/**
   35: 	 * Public members of ipsec_policy_mgr_t.
   36: 	 */
   37: 	ipsec_policy_mgr_t public;
   38: 
   39: 	/**
   40: 	 * Installed policies (ipsec_policy_entry_t*)
   41: 	 */
   42: 	linked_list_t *policies;
   43: 
   44: 	/**
   45: 	 * Lock to safely access the list of policies
   46: 	 */
   47: 	rwlock_t *lock;
   48: 
   49: };
   50: 
   51: /**
   52:  * Helper struct to store policies in a list sorted by the same pseudo-priority
   53:  * used by the NETLINK kernel interface.
   54:  */
   55: typedef struct {
   56: 
   57: 	/**
   58: 	 * Priority used to sort policies
   59: 	 */
   60: 	uint32_t priority;
   61: 
   62: 	/**
   63: 	 * The policy
   64: 	 */
   65: 	ipsec_policy_t *policy;
   66: 
   67: } ipsec_policy_entry_t;
   68: 
   69: /**
   70:  * Calculate the pseudo-priority to sort policies.  This is the same algorithm
   71:  * used by the NETLINK kernel interface (i.e. high priority -> low value).
   72:  */
   73: static uint32_t calculate_priority(policy_priority_t policy_priority,
   74: 									traffic_selector_t *src,
   75: 									traffic_selector_t *dst)
   76: {
   77: 	uint32_t priority = PRIO_BASE;
   78: 	uint16_t port;
   79: 	uint8_t mask, proto;
   80: 	host_t *net;
   81: 
   82: 	switch (policy_priority)
   83: 	{
   84: 		case POLICY_PRIORITY_FALLBACK:
   85: 			priority <<= 1;
   86: 			/* fall-through */
   87: 		case POLICY_PRIORITY_ROUTED:
   88: 			priority <<= 1;
   89: 			/* fall-through */
   90: 		case POLICY_PRIORITY_DEFAULT:
   91: 			priority <<= 1;
   92: 			/* fall-through */
   93: 		case POLICY_PRIORITY_PASS:
   94: 			break;
   95: 	}
   96: 	/* calculate priority based on selector size, small size = high prio */
   97: 	src->to_subnet(src, &net, &mask);
   98: 	priority -= mask;
   99: 	proto = src->get_protocol(src);
  100: 	port = net->get_port(net);
  101: 	net->destroy(net);
  102: 
  103: 	dst->to_subnet(dst, &net, &mask);
  104: 	priority -= mask;
  105: 	proto = max(proto, dst->get_protocol(dst));
  106: 	port = max(port, net->get_port(net));
  107: 	net->destroy(net);
  108: 
  109: 	priority <<= 2; /* make some room for the two flags */
  110: 	priority += port ? 0 : 2;
  111: 	priority += proto ? 0 : 1;
  112: 	return priority;
  113: }
  114: 
  115: /**
  116:  * Create a policy entry
  117:  */
  118: static ipsec_policy_entry_t *policy_entry_create(ipsec_policy_t *policy)
  119: {
  120: 	ipsec_policy_entry_t *this;
  121: 
  122: 	INIT(this,
  123: 		.policy = policy,
  124: 		.priority = calculate_priority(policy->get_priority(policy),
  125: 									   policy->get_source_ts(policy),
  126: 									   policy->get_destination_ts(policy)),
  127: 	);
  128: 	return this;
  129: }
  130: 
  131: /**
  132:  * Destroy a policy entry
  133:  */
  134: static void policy_entry_destroy(ipsec_policy_entry_t *this)
  135: {
  136: 	this->policy->destroy(this->policy);
  137: 	free(this);
  138: }
  139: 
  140: METHOD(ipsec_policy_mgr_t, add_policy, status_t,
  141: 	private_ipsec_policy_mgr_t *this, host_t *src, host_t *dst,
  142: 	traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
  143: 	policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
  144: 	policy_priority_t priority)
  145: {
  146: 	enumerator_t *enumerator;
  147: 	ipsec_policy_entry_t *entry, *current;
  148: 	ipsec_policy_t *policy;
  149: 
  150: 	if (type != POLICY_IPSEC || direction == POLICY_FWD)
  151: 	{	/* we ignore these policies as we currently have no use for them */
  152: 		return SUCCESS;
  153: 	}
  154: 
  155: 	DBG2(DBG_ESP, "adding policy %R === %R %N", src_ts, dst_ts,
  156: 		 policy_dir_names, direction);
  157: 
  158: 	policy = ipsec_policy_create(src, dst, src_ts, dst_ts, direction, type, sa,
  159: 								 mark, priority);
  160: 	entry = policy_entry_create(policy);
  161: 
  162: 	this->lock->write_lock(this->lock);
  163: 	enumerator = this->policies->create_enumerator(this->policies);
  164: 	while (enumerator->enumerate(enumerator, (void**)&current))
  165: 	{
  166: 		if (current->priority >= entry->priority)
  167: 		{
  168: 			break;
  169: 		}
  170: 	}
  171: 	this->policies->insert_before(this->policies, enumerator, entry);
  172: 	enumerator->destroy(enumerator);
  173: 	this->lock->unlock(this->lock);
  174: 	return SUCCESS;
  175: }
  176: 
  177: METHOD(ipsec_policy_mgr_t, del_policy, status_t,
  178: 	private_ipsec_policy_mgr_t *this, host_t *src, host_t *dst,
  179: 	traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
  180: 	policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
  181: 	policy_priority_t policy_priority)
  182: {
  183: 	enumerator_t *enumerator;
  184: 	ipsec_policy_entry_t *current, *found = NULL;
  185: 	uint32_t priority;
  186: 
  187: 	if (type != POLICY_IPSEC || direction == POLICY_FWD)
  188: 	{	/* we ignore these policies as we currently have no use for them */
  189: 		return SUCCESS;
  190: 	}
  191: 	DBG2(DBG_ESP, "deleting policy %R === %R %N", src_ts, dst_ts,
  192: 		 policy_dir_names, direction);
  193: 
  194: 	priority = calculate_priority(policy_priority, src_ts, dst_ts);
  195: 
  196: 	this->lock->write_lock(this->lock);
  197: 	enumerator = this->policies->create_enumerator(this->policies);
  198: 	while (enumerator->enumerate(enumerator, (void**)&current))
  199: 	{
  200: 		if (current->priority == priority &&
  201: 			current->policy->match(current->policy, src_ts, dst_ts, direction,
  202: 								   sa->reqid, mark, policy_priority))
  203: 		{
  204: 			this->policies->remove_at(this->policies, enumerator);
  205: 			found = current;
  206: 			break;
  207: 		}
  208: 	}
  209: 	enumerator->destroy(enumerator);
  210: 	this->lock->unlock(this->lock);
  211: 	if (found)
  212: 	{
  213: 		policy_entry_destroy(found);
  214: 		return SUCCESS;
  215: 	}
  216: 	return FAILED;
  217: }
  218: 
  219: METHOD(ipsec_policy_mgr_t, flush_policies, status_t,
  220: 	private_ipsec_policy_mgr_t *this)
  221: {
  222: 	ipsec_policy_entry_t *entry;
  223: 
  224: 	DBG2(DBG_ESP, "flushing policies");
  225: 
  226: 	this->lock->write_lock(this->lock);
  227: 	while (this->policies->remove_last(this->policies,
  228: 									  (void**)&entry) == SUCCESS)
  229: 	{
  230: 		policy_entry_destroy(entry);
  231: 	}
  232: 	this->lock->unlock(this->lock);
  233: 	return SUCCESS;
  234: }
  235: 
  236: METHOD(ipsec_policy_mgr_t, find_by_packet, ipsec_policy_t*,
  237: 	private_ipsec_policy_mgr_t *this, ip_packet_t *packet, bool inbound,
  238: 	uint32_t reqid)
  239: {
  240: 	enumerator_t *enumerator;
  241: 	ipsec_policy_entry_t *current;
  242: 	ipsec_policy_t *found = NULL;
  243: 
  244: 	this->lock->read_lock(this->lock);
  245: 	enumerator = this->policies->create_enumerator(this->policies);
  246: 	while (enumerator->enumerate(enumerator, (void**)&current))
  247: 	{
  248: 		ipsec_policy_t *policy = current->policy;
  249: 
  250: 		if ((inbound == (policy->get_direction(policy) == POLICY_IN)) &&
  251: 			 policy->match_packet(policy, packet))
  252: 		{
  253: 			if (reqid == 0 || reqid == policy->get_reqid(policy))
  254: 			{
  255: 				found = policy->get_ref(policy);
  256: 				break;
  257: 			}
  258: 		}
  259: 	}
  260: 	enumerator->destroy(enumerator);
  261: 	this->lock->unlock(this->lock);
  262: 	return found;
  263: }
  264: 
  265: METHOD(ipsec_policy_mgr_t, destroy, void,
  266: 	private_ipsec_policy_mgr_t *this)
  267: {
  268: 	flush_policies(this);
  269: 	this->policies->destroy(this->policies);
  270: 	this->lock->destroy(this->lock);
  271: 	free(this);
  272: }
  273: 
  274: /**
  275:  * Described in header.
  276:  */
  277: ipsec_policy_mgr_t *ipsec_policy_mgr_create()
  278: {
  279: 	private_ipsec_policy_mgr_t *this;
  280: 
  281: 	INIT(this,
  282: 		.public = {
  283: 			.add_policy = _add_policy,
  284: 			.del_policy = _del_policy,
  285: 			.flush_policies = _flush_policies,
  286: 			.find_by_packet = _find_by_packet,
  287: 			.destroy = _destroy,
  288: 		},
  289: 		.policies = linked_list_create(),
  290: 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
  291: 	);
  292: 
  293: 	return &this->public;
  294: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>