Annotation of embedaddon/strongswan/src/libipsec/ipsec_policy_mgr.c, revision 1.1.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>