71fadbdfaee23c08d1a9a457d622187262c65f83
[strongswan.git] / src / charon / config / policies / policy.c
1 /**
2 * @file policy.c
3 *
4 * @brief Implementation of policy_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <time.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "policy.h"
29
30 #include <utils/linked_list.h>
31 #include <utils/identification.h>
32 #include <utils/logger_manager.h>
33
34 typedef struct private_policy_t private_policy_t;
35
36 /**
37 * Private data of an policy_t object
38 */
39 struct private_policy_t {
40
41 /**
42 * Public part
43 */
44 policy_t public;
45
46 /**
47 * Number of references hold by others to this policy
48 */
49 refcount_t refcount;
50
51 /**
52 * Name of the policy, used to query it
53 */
54 char *name;
55
56 /**
57 * id to use to identify us
58 */
59 identification_t *my_id;
60
61 /**
62 * allowed id for other
63 */
64 identification_t *other_id;
65
66 /**
67 * we have a cert issued by this CA
68 */
69 identification_t *my_ca;
70
71 /**
72 * we require the other end to have a cert issued by this CA
73 */
74 identification_t *other_ca;
75
76 /**
77 * updown script
78 */
79 char *updown;
80
81 /**
82 * list for all proposals
83 */
84 linked_list_t *proposals;
85
86 /**
87 * list for traffic selectors for my site
88 */
89 linked_list_t *my_ts;
90
91 /**
92 * list for traffic selectors for others site
93 */
94 linked_list_t *other_ts;
95
96 /**
97 * Time before an SA gets invalid
98 */
99 u_int32_t soft_lifetime;
100
101 /**
102 * Time before an SA gets rekeyed
103 */
104 u_int32_t hard_lifetime;
105
106 /**
107 * Time, which specifies the range of a random value
108 * substracted from soft_lifetime.
109 */
110 u_int32_t jitter;
111
112 /**
113 * Should the SA get ROUTED when peer detected as dead?
114 */
115 bool dpd_route;
116
117 /**
118 * logger
119 */
120 logger_t *logger;
121 };
122
123 /**
124 * Implementation of policy_t.get_name
125 */
126 static char *get_name(private_policy_t *this)
127 {
128 return this->name;
129 }
130
131 /**
132 * Implementation of policy_t.get_my_id
133 */
134 static identification_t *get_my_id(private_policy_t *this)
135 {
136 return this->my_id;
137 }
138
139 /**
140 * Implementation of policy_t.get_other_id
141 */
142 static identification_t *get_other_id(private_policy_t *this)
143 {
144 return this->other_id;
145 }
146
147 /**
148 * Get traffic selectors, with wildcard-address update
149 */
150 static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_t *list, host_t *host)
151 {
152 iterator_t *iterator;
153 traffic_selector_t *current;
154 linked_list_t *result = linked_list_create();
155
156 iterator = list->create_iterator(list, TRUE);
157
158 while (iterator->iterate(iterator, (void**)&current))
159 {
160 /* we make a copy of the TS, this allows us to update wildcard
161 * addresses in it. We won't pollute the shared policy. */
162 current = current->clone(current);
163 current->update_address_range(current, host);
164
165 result->insert_last(result, (void*)current);
166 }
167 iterator->destroy(iterator);
168 return result;
169 }
170
171 /**
172 * Implementation of policy_t.get_my_traffic_selectors
173 */
174 static linked_list_t *get_my_traffic_selectors(private_policy_t *this, host_t *me)
175 {
176 return get_traffic_selectors(this, this->my_ts, me);
177 }
178
179 /**
180 * Implementation of policy_t.get_other_traffic_selectors
181 */
182 static linked_list_t *get_other_traffic_selectors(private_policy_t *this, host_t *other)
183 {
184 return get_traffic_selectors(this, this->other_ts, other);
185 }
186
187 /**
188 * Narrow traffic selectors, with wildcard-address update in "stored".
189 */
190 static linked_list_t *select_traffic_selectors(private_policy_t *this,
191 linked_list_t *stored,
192 linked_list_t *supplied,
193 host_t *host)
194 {
195 iterator_t *supplied_iter, *stored_iter;
196 traffic_selector_t *supplied_ts, *stored_ts, *selected_ts;
197 linked_list_t *selected = linked_list_create();
198
199 this->logger->log(this->logger, CONTROL|LEVEL1,
200 "selecting traffic selectors for %s host",
201 stored == this->my_ts ? "local" : "remote");
202
203 stored_iter = stored->create_iterator(stored, TRUE);
204 supplied_iter = supplied->create_iterator(supplied, TRUE);
205
206 /* iterate over all stored selectors */
207 while (stored_iter->iterate(stored_iter, (void**)&stored_ts))
208 {
209 /* we make a copy of the TS, this allows us to update wildcard
210 * addresses in it. We won't pollute the shared policy. */
211 stored_ts = stored_ts->clone(stored_ts);
212 stored_ts->update_address_range(stored_ts, host);
213
214 supplied_iter->reset(supplied_iter);
215 /* iterate over all supplied traffic selectors */
216 while (supplied_iter->iterate(supplied_iter, (void**)&supplied_ts))
217 {
218 this->logger->log(this->logger, CONTROL|LEVEL2,
219 " stored %s <=> %s received",
220 stored_ts->get_string(stored_ts),
221 supplied_ts->get_string(supplied_ts));
222
223 selected_ts = stored_ts->get_subset(stored_ts, supplied_ts);
224 if (selected_ts)
225 {
226 /* got a match, add to list */
227 selected->insert_last(selected, (void*)selected_ts);
228
229 this->logger->log(this->logger, CONTROL|LEVEL1, " got a match: %s",
230 selected_ts->get_string(selected_ts));
231 }
232 }
233 stored_ts->destroy(stored_ts);
234 }
235 stored_iter->destroy(stored_iter);
236 supplied_iter->destroy(supplied_iter);
237
238 return selected;
239 }
240
241 /**
242 * Implementation of private_policy_t.select_my_traffic_selectors
243 */
244 static linked_list_t *select_my_traffic_selectors(private_policy_t *this,
245 linked_list_t *supplied,
246 host_t *me)
247 {
248 return select_traffic_selectors(this, this->my_ts, supplied, me);
249 }
250
251 /**
252 * Implementation of private_policy_t.select_other_traffic_selectors
253 */
254 static linked_list_t *select_other_traffic_selectors(private_policy_t *this,
255 linked_list_t *supplied,
256 host_t* other)
257 {
258 return select_traffic_selectors(this, this->other_ts, supplied, other);
259 }
260
261 /**
262 * Implementation of policy_t.get_proposal_iterator
263 */
264 static linked_list_t *get_proposals(private_policy_t *this)
265 {
266 iterator_t *iterator;
267 proposal_t *current;
268 linked_list_t *proposals = linked_list_create();
269
270 iterator = this->proposals->create_iterator(this->proposals, TRUE);
271 while (iterator->iterate(iterator, (void**)&current))
272 {
273 current = current->clone(current);
274 proposals->insert_last(proposals, (void*)current);
275 }
276 iterator->destroy(iterator);
277
278 return proposals;
279 }
280
281 /**
282 * Implementation of policy_t.select_proposal
283 */
284 static proposal_t *select_proposal(private_policy_t *this, linked_list_t *proposals)
285 {
286 iterator_t *stored_iter, *supplied_iter;
287 proposal_t *stored, *supplied, *selected;
288
289 stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
290 supplied_iter = proposals->create_iterator(proposals, TRUE);
291
292 /* compare all stored proposals with all supplied. Stored ones are preferred. */
293 while (stored_iter->has_next(stored_iter))
294 {
295 supplied_iter->reset(supplied_iter);
296 stored_iter->current(stored_iter, (void**)&stored);
297
298 while (supplied_iter->has_next(supplied_iter))
299 {
300 supplied_iter->current(supplied_iter, (void**)&supplied);
301 selected = stored->select(stored, supplied);
302 if (selected)
303 {
304 /* they match, return */
305 stored_iter->destroy(stored_iter);
306 supplied_iter->destroy(supplied_iter);
307 return selected;
308 }
309 }
310 }
311
312 /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
313 stored_iter->destroy(stored_iter);
314 supplied_iter->destroy(supplied_iter);
315
316 return NULL;
317 }
318
319 /**
320 * Implementation of policy_t.add_authorities
321 */
322 static void add_authorities(private_policy_t *this, identification_t *my_ca, identification_t *other_ca)
323 {
324 this->my_ca = my_ca;
325 this->other_ca = other_ca;
326 }
327
328 /**
329 * Implementation of policy_t.get_updown
330 */
331 static char* get_updown(private_policy_t *this)
332 {
333 return this->updown;
334 }
335
336 /**
337 * Implementation of policy_t.add_my_traffic_selector
338 */
339 static void add_my_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
340 {
341 this->my_ts->insert_last(this->my_ts, (void*)traffic_selector);
342 }
343
344 /**
345 * Implementation of policy_t.add_other_traffic_selector
346 */
347 static void add_other_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
348 {
349 this->other_ts->insert_last(this->other_ts, (void*)traffic_selector);
350 }
351
352 /**
353 * Implementation of policy_t.add_proposal
354 */
355 static void add_proposal(private_policy_t *this, proposal_t *proposal)
356 {
357 this->proposals->insert_last(this->proposals, (void*)proposal);
358 }
359
360 /**
361 * Implementation of policy_t.get_soft_lifetime
362 */
363 static u_int32_t get_soft_lifetime(private_policy_t *this)
364 {
365 if (this->jitter == 0)
366 {
367 return this->soft_lifetime ;
368 }
369 return this->soft_lifetime - (random() % this->jitter);
370 }
371
372 /**
373 * Implementation of policy_t.get_hard_lifetime
374 */
375 static u_int32_t get_hard_lifetime(private_policy_t *this)
376 {
377 return this->hard_lifetime;
378 }
379
380 /**
381 * Implements policy_t.get_ref.
382 */
383 static void get_ref(private_policy_t *this)
384 {
385 ref_get(&this->refcount);
386 }
387
388 /**
389 * Implements policy_t.destroy.
390 */
391 static void destroy(private_policy_t *this)
392 {
393 if (ref_put(&this->refcount))
394 {
395 proposal_t *proposal;
396 traffic_selector_t *traffic_selector;
397
398 /* delete proposals */
399 while(this->proposals->remove_last(this->proposals, (void**)&proposal) == SUCCESS)
400 {
401 proposal->destroy(proposal);
402 }
403 this->proposals->destroy(this->proposals);
404
405 /* delete traffic selectors */
406 while(this->my_ts->remove_last(this->my_ts, (void**)&traffic_selector) == SUCCESS)
407 {
408 traffic_selector->destroy(traffic_selector);
409 }
410 this->my_ts->destroy(this->my_ts);
411
412 /* delete traffic selectors */
413 while(this->other_ts->remove_last(this->other_ts, (void**)&traffic_selector) == SUCCESS)
414 {
415 traffic_selector->destroy(traffic_selector);
416 }
417 this->other_ts->destroy(this->other_ts);
418
419 /* delete certification authorities */
420 if (this->my_ca)
421 {
422 this->my_ca->destroy(this->my_ca);
423 }
424 if (this->other_ca)
425 {
426 this->other_ca->destroy(this->other_ca);
427 }
428
429 /* delete updown script */
430 if (this->updown)
431 {
432 free(this->updown);
433 }
434
435 /* delete ids */
436 this->my_id->destroy(this->my_id);
437 this->other_id->destroy(this->other_id);
438
439 free(this->name);
440 free(this);
441 }
442 }
443
444 /*
445 * Described in header-file
446 */
447 policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
448 u_int32_t hard_lifetime, u_int32_t soft_lifetime,
449 u_int32_t jitter, char *updown, bool dpd_route)
450 {
451 private_policy_t *this = malloc_thing(private_policy_t);
452
453 /* public functions */
454 this->public.get_name = (char *(*)(policy_t*))get_name;
455 this->public.get_my_id = (identification_t*(*)(policy_t*))get_my_id;
456 this->public.get_other_id = (identification_t*(*)(policy_t*))get_other_id;
457 this->public.get_my_traffic_selectors = (linked_list_t*(*)(policy_t*,host_t*))get_my_traffic_selectors;
458 this->public.get_other_traffic_selectors = (linked_list_t*(*)(policy_t*,host_t*))get_other_traffic_selectors;
459 this->public.select_my_traffic_selectors = (linked_list_t*(*)(policy_t*,linked_list_t*,host_t*))select_my_traffic_selectors;
460 this->public.select_other_traffic_selectors = (linked_list_t*(*)(policy_t*,linked_list_t*,host_t*))select_other_traffic_selectors;
461 this->public.get_proposals = (linked_list_t*(*)(policy_t*))get_proposals;
462 this->public.select_proposal = (proposal_t*(*)(policy_t*,linked_list_t*))select_proposal;
463 this->public.add_my_traffic_selector = (void(*)(policy_t*,traffic_selector_t*))add_my_traffic_selector;
464 this->public.add_other_traffic_selector = (void(*)(policy_t*,traffic_selector_t*))add_other_traffic_selector;
465 this->public.add_proposal = (void(*)(policy_t*,proposal_t*))add_proposal;
466 this->public.add_authorities = (void(*)(policy_t*,identification_t*, identification_t*))add_authorities;
467 this->public.get_updown = (char*(*)(policy_t*))get_updown;
468 this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
469 this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
470 this->public.get_ref = (void(*)(policy_t*))get_ref;
471 this->public.destroy = (void(*)(policy_t*))destroy;
472
473 /* apply init values */
474 this->name = strdup(name);
475 this->my_id = my_id;
476 this->other_id = other_id;
477 this->hard_lifetime = hard_lifetime;
478 this->soft_lifetime = soft_lifetime;
479 this->jitter = jitter;
480 this->updown = (updown == NULL) ? NULL : strdup(updown);
481 this->dpd_route = dpd_route;
482
483 /* initialize private members*/
484 this->refcount = 1;
485 this->my_ca = NULL;
486 this->other_ca = NULL;
487 this->proposals = linked_list_create();
488 this->my_ts = linked_list_create();
489 this->other_ts = linked_list_create();
490 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
491
492 return &this->public;
493 }