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