Annotation of embedaddon/strongswan/src/libipsec/ipsec_policy_mgr.c, revision 1.1
1.1 ! misho 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**)¤t))
! 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**)¤t))
! 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**)¤t))
! 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>