libipsec: Properly initialize variables when creating AEAD wrapper
[strongswan.git] / src / libipsec / ipsec_policy_mgr.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * 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 512
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 u_int32_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 u_int32_t calculate_priority(policy_priority_t policy_priority,
74 traffic_selector_t *src,
75 traffic_selector_t *dst)
76 {
77 u_int32_t priority = PRIO_BASE;
78 u_int16_t port;
79 u_int8_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 break;
92 }
93 /* calculate priority based on selector size, small size = high prio */
94 src->to_subnet(src, &net, &mask);
95 priority -= mask;
96 proto = src->get_protocol(src);
97 port = net->get_port(net);
98 net->destroy(net);
99
100 dst->to_subnet(dst, &net, &mask);
101 priority -= mask;
102 proto = max(proto, dst->get_protocol(dst));
103 port = max(port, net->get_port(net));
104 net->destroy(net);
105
106 priority <<= 2; /* make some room for the two flags */
107 priority += port ? 0 : 2;
108 priority += proto ? 0 : 1;
109 return priority;
110 }
111
112 /**
113 * Create a policy entry
114 */
115 static ipsec_policy_entry_t *policy_entry_create(ipsec_policy_t *policy)
116 {
117 ipsec_policy_entry_t *this;
118
119 INIT(this,
120 .policy = policy,
121 .priority = calculate_priority(policy->get_priority(policy),
122 policy->get_source_ts(policy),
123 policy->get_destination_ts(policy)),
124 );
125 return this;
126 }
127
128 /**
129 * Destroy a policy entry
130 */
131 static void policy_entry_destroy(ipsec_policy_entry_t *this)
132 {
133 this->policy->destroy(this->policy);
134 free(this);
135 }
136
137 METHOD(ipsec_policy_mgr_t, add_policy, status_t,
138 private_ipsec_policy_mgr_t *this, host_t *src, host_t *dst,
139 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
140 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
141 policy_priority_t priority)
142 {
143 enumerator_t *enumerator;
144 ipsec_policy_entry_t *entry, *current;
145 ipsec_policy_t *policy;
146
147 if (type != POLICY_IPSEC || direction == POLICY_FWD)
148 { /* we ignore these policies as we currently have no use for them */
149 return SUCCESS;
150 }
151
152 DBG2(DBG_ESP, "adding policy %R === %R %N", src_ts, dst_ts,
153 policy_dir_names, direction);
154
155 policy = ipsec_policy_create(src, dst, src_ts, dst_ts, direction, type, sa,
156 mark, priority);
157 entry = policy_entry_create(policy);
158
159 this->lock->write_lock(this->lock);
160 enumerator = this->policies->create_enumerator(this->policies);
161 while (enumerator->enumerate(enumerator, (void**)&current))
162 {
163 if (current->priority >= entry->priority)
164 {
165 break;
166 }
167 }
168 this->policies->insert_before(this->policies, enumerator, entry);
169 enumerator->destroy(enumerator);
170 this->lock->unlock(this->lock);
171 return SUCCESS;
172 }
173
174 METHOD(ipsec_policy_mgr_t, del_policy, status_t,
175 private_ipsec_policy_mgr_t *this, traffic_selector_t *src_ts,
176 traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
177 mark_t mark, policy_priority_t policy_priority)
178 {
179 enumerator_t *enumerator;
180 ipsec_policy_entry_t *current, *found = NULL;
181 u_int32_t priority;
182
183 if (direction == POLICY_FWD)
184 { /* we ignore these policies as we currently have no use for them */
185 return SUCCESS;
186 }
187 DBG2(DBG_ESP, "deleting policy %R === %R %N", src_ts, dst_ts,
188 policy_dir_names, direction);
189
190 priority = calculate_priority(policy_priority, src_ts, dst_ts);
191
192 this->lock->write_lock(this->lock);
193 enumerator = this->policies->create_enumerator(this->policies);
194 while (enumerator->enumerate(enumerator, (void**)&current))
195 {
196 if (current->priority == priority &&
197 current->policy->match(current->policy, src_ts, dst_ts, direction,
198 reqid, mark, policy_priority))
199 {
200 this->policies->remove_at(this->policies, enumerator);
201 found = current;
202 break;
203 }
204 }
205 enumerator->destroy(enumerator);
206 this->lock->unlock(this->lock);
207 if (found)
208 {
209 policy_entry_destroy(found);
210 return SUCCESS;
211 }
212 return FAILED;
213 }
214
215 METHOD(ipsec_policy_mgr_t, flush_policies, status_t,
216 private_ipsec_policy_mgr_t *this)
217 {
218 ipsec_policy_entry_t *entry;
219
220 DBG2(DBG_ESP, "flushing policies");
221
222 this->lock->write_lock(this->lock);
223 while (this->policies->remove_last(this->policies,
224 (void**)&entry) == SUCCESS)
225 {
226 policy_entry_destroy(entry);
227 }
228 this->lock->unlock(this->lock);
229 return SUCCESS;
230 }
231
232 METHOD(ipsec_policy_mgr_t, find_by_packet, ipsec_policy_t*,
233 private_ipsec_policy_mgr_t *this, ip_packet_t *packet, bool inbound)
234 {
235 enumerator_t *enumerator;
236 ipsec_policy_entry_t *current;
237 ipsec_policy_t *found = NULL;
238
239 this->lock->read_lock(this->lock);
240 enumerator = this->policies->create_enumerator(this->policies);
241 while (enumerator->enumerate(enumerator, (void**)&current))
242 {
243 ipsec_policy_t *policy = current->policy;
244
245 if ((inbound == (policy->get_direction(policy) == POLICY_IN)) &&
246 policy->match_packet(policy, packet))
247 {
248 found = policy->get_ref(policy);
249 break;
250 }
251 }
252 enumerator->destroy(enumerator);
253 this->lock->unlock(this->lock);
254 return found;
255 }
256
257 METHOD(ipsec_policy_mgr_t, destroy, void,
258 private_ipsec_policy_mgr_t *this)
259 {
260 flush_policies(this);
261 this->policies->destroy(this->policies);
262 this->lock->destroy(this->lock);
263 free(this);
264 }
265
266 /**
267 * Described in header.
268 */
269 ipsec_policy_mgr_t *ipsec_policy_mgr_create()
270 {
271 private_ipsec_policy_mgr_t *this;
272
273 INIT(this,
274 .public = {
275 .add_policy = _add_policy,
276 .del_policy = _del_policy,
277 .flush_policies = _flush_policies,
278 .find_by_packet = _find_by_packet,
279 .destroy = _destroy,
280 },
281 .policies = linked_list_create(),
282 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
283 );
284
285 return &this->public;
286 }