Return to ipsec_policy_mgr.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libipsec |
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: }