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