Annotation of embedaddon/strongswan/src/libcharon/config/child_cfg.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2008-2019 Tobias Brunner
3: * Copyright (C) 2016 Andreas Steffen
4: * Copyright (C) 2005-2007 Martin Willi
5: * Copyright (C) 2005 Jan Hutter
6: * HSR Hochschule fuer Technik Rapperswil
7: *
8: * This program is free software; you can redistribute it and/or modify it
9: * under the terms of the GNU General Public License as published by the
10: * Free Software Foundation; either version 2 of the License, or (at your
11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12: *
13: * This program is distributed in the hope that it will be useful, but
14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16: * for more details.
17: */
18:
19: #include "child_cfg.h"
20:
21: #include <stdint.h>
22:
23: #include <daemon.h>
24:
25: ENUM(action_names, ACTION_NONE, ACTION_RESTART,
26: "clear",
27: "hold",
28: "restart",
29: );
30:
31: /** Default replay window size, if not set using charon.replay_window */
32: #define DEFAULT_REPLAY_WINDOW 32
33:
34: typedef struct private_child_cfg_t private_child_cfg_t;
35:
36: /**
37: * Private data of an child_cfg_t object
38: */
39: struct private_child_cfg_t {
40:
41: /**
42: * Public part
43: */
44: child_cfg_t public;
45:
46: /**
47: * Number of references hold by others to this child_cfg
48: */
49: refcount_t refcount;
50:
51: /**
52: * Name of the child_cfg, used to query it
53: */
54: char *name;
55:
56: /**
57: * Options
58: */
59: child_cfg_option_t options;
60:
61: /**
62: * list for all proposals
63: */
64: linked_list_t *proposals;
65:
66: /**
67: * list for traffic selectors for my site
68: */
69: linked_list_t *my_ts;
70:
71: /**
72: * list for traffic selectors for others site
73: */
74: linked_list_t *other_ts;
75:
76: /**
77: * updown script
78: */
79: char *updown;
80:
81: /**
82: * Mode to propose for a initiated CHILD: tunnel/transport
83: */
84: ipsec_mode_t mode;
85:
86: /**
87: * action to take to start CHILD_SA
88: */
89: action_t start_action;
90:
91: /**
92: * action to take on DPD
93: */
94: action_t dpd_action;
95:
96: /**
97: * action to take on CHILD_SA close
98: */
99: action_t close_action;
100:
101: /**
102: * CHILD_SA lifetime config
103: */
104: lifetime_cfg_t lifetime;
105:
106: /**
107: * Inactivity timeout
108: */
109: uint32_t inactivity;
110:
111: /**
112: * Reqid to install CHILD_SA with
113: */
114: uint32_t reqid;
115:
116: /**
117: * Optional interface ID to use for inbound CHILD_SA
118: */
119: uint32_t if_id_in;
120:
121: /**
122: * Optional interface ID to use for outbound CHILD_SA
123: */
124: uint32_t if_id_out;
125:
126: /**
127: * Optional mark to install inbound CHILD_SA with
128: */
129: mark_t mark_in;
130:
131: /**
132: * Optional mark to install outbound CHILD_SA with
133: */
134: mark_t mark_out;
135:
136: /**
137: * Optional mark to set to packets after inbound processing
138: */
139: mark_t set_mark_in;
140:
141: /**
142: * Optional mark to set to packets after outbound processing
143: */
144: mark_t set_mark_out;
145:
146: /**
147: * Traffic Flow Confidentiality padding, if enabled
148: */
149: uint32_t tfc;
150:
151: /**
152: * Optional manually-set IPsec policy priorities
153: */
154: uint32_t manual_prio;
155:
156: /**
157: * Optional restriction of IPsec policy to a given network interface
158: */
159: char *interface;
160:
161: /**
162: * anti-replay window size
163: */
164: uint32_t replay_window;
165:
166: /**
167: * HW offload mode
168: */
169: hw_offload_t hw_offload;
170:
171: /**
172: * DS header field copy mode
173: */
174: dscp_copy_t copy_dscp;
175: };
176:
177: METHOD(child_cfg_t, get_name, char*,
178: private_child_cfg_t *this)
179: {
180: return this->name;
181: }
182:
183: METHOD(child_cfg_t, has_option, bool,
184: private_child_cfg_t *this, child_cfg_option_t option)
185: {
186: return this->options & option;
187: }
188:
189: METHOD(child_cfg_t, add_proposal, void,
190: private_child_cfg_t *this, proposal_t *proposal)
191: {
192: if (proposal)
193: {
194: this->proposals->insert_last(this->proposals, proposal);
195: }
196: }
197:
198: CALLBACK(match_proposal, bool,
199: proposal_t *item, va_list args)
200: {
201: proposal_t *proposal;
202:
203: VA_ARGS_VGET(args, proposal);
204: return item->equals(item, proposal);
205: }
206:
207: METHOD(child_cfg_t, get_proposals, linked_list_t*,
208: private_child_cfg_t *this, bool strip_dh)
209: {
210: enumerator_t *enumerator;
211: proposal_t *current;
212: proposal_selection_flag_t flags = 0;
213: linked_list_t *proposals = linked_list_create();
214:
215: if (strip_dh)
216: {
217: flags |= PROPOSAL_SKIP_DH;
218: }
219:
220: enumerator = this->proposals->create_enumerator(this->proposals);
221: while (enumerator->enumerate(enumerator, ¤t))
222: {
223: current = current->clone(current, flags);
224: if (proposals->find_first(proposals, match_proposal, NULL, current))
225: {
226: current->destroy(current);
227: continue;
228: }
229: proposals->insert_last(proposals, current);
230: }
231: enumerator->destroy(enumerator);
232:
233: DBG2(DBG_CFG, "configured proposals: %#P", proposals);
234:
235: return proposals;
236: }
237:
238: METHOD(child_cfg_t, select_proposal, proposal_t*,
239: private_child_cfg_t*this, linked_list_t *proposals,
240: proposal_selection_flag_t flags)
241: {
242: return proposal_select(this->proposals, proposals, flags);
243: }
244:
245: METHOD(child_cfg_t, add_traffic_selector, void,
246: private_child_cfg_t *this, bool local, traffic_selector_t *ts)
247: {
248: if (local)
249: {
250: this->my_ts->insert_last(this->my_ts, ts);
251: }
252: else
253: {
254: this->other_ts->insert_last(this->other_ts, ts);
255: }
256: }
257:
258: METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
259: private_child_cfg_t *this, bool local, linked_list_t *supplied,
260: linked_list_t *hosts, bool log)
261: {
262: enumerator_t *e1, *e2;
263: traffic_selector_t *ts1, *ts2, *selected;
264: linked_list_t *result, *derived;
265: host_t *host;
266:
267: result = linked_list_create();
268: derived = linked_list_create();
269: if (local)
270: {
271: e1 = this->my_ts->create_enumerator(this->my_ts);
272: }
273: else
274: {
275: e1 = this->other_ts->create_enumerator(this->other_ts);
276: }
277: /* in a first step, replace "dynamic" TS with the host list */
278: while (e1->enumerate(e1, &ts1))
279: {
280: if (hosts && hosts->get_count(hosts))
281: { /* set hosts if TS is dynamic or as initiator in transport mode */
282: bool dynamic = ts1->is_dynamic(ts1),
283: proxy_mode = has_option(this, OPT_PROXY_MODE);
284: if (dynamic || (this->mode == MODE_TRANSPORT && !proxy_mode &&
285: !supplied))
286: {
287: e2 = hosts->create_enumerator(hosts);
288: while (e2->enumerate(e2, &host))
289: {
290: ts2 = ts1->clone(ts1);
291: if (dynamic || !host->is_anyaddr(host))
292: { /* don't make regular TS larger than they were */
293: ts2->set_address(ts2, host);
294: }
295: derived->insert_last(derived, ts2);
296: }
297: e2->destroy(e2);
298: continue;
299: }
300: }
301: derived->insert_last(derived, ts1->clone(ts1));
302: }
303: e1->destroy(e1);
304:
305: if (log)
306: {
307: DBG2(DBG_CFG, "%s traffic selectors for %s:",
308: supplied ? "selecting" : "proposing", local ? "us" : "other");
309: }
310: if (!supplied)
311: {
312: while (derived->remove_first(derived, (void**)&ts1) == SUCCESS)
313: {
314: if (log)
315: {
316: DBG2(DBG_CFG, " %R", ts1);
317: }
318: result->insert_last(result, ts1);
319: }
320: derived->destroy(derived);
321: }
322: else
323: {
324: e1 = derived->create_enumerator(derived);
325: e2 = supplied->create_enumerator(supplied);
326: /* enumerate all configured/derived selectors */
327: while (e1->enumerate(e1, &ts1))
328: {
329: /* enumerate all supplied traffic selectors */
330: while (e2->enumerate(e2, &ts2))
331: {
332: selected = ts1->get_subset(ts1, ts2);
333: if (selected)
334: {
335: if (log)
336: {
337: DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
338: ts1, ts2, selected);
339: }
340: result->insert_last(result, selected);
341: }
342: else if (log)
343: {
344: DBG2(DBG_CFG, " config: %R, received: %R => no match",
345: ts1, ts2);
346: }
347: }
348: supplied->reset_enumerator(supplied, e2);
349: }
350: e1->destroy(e1);
351: e2->destroy(e2);
352:
353: /* check if we/peer did any narrowing, raise alert */
354: e1 = derived->create_enumerator(derived);
355: e2 = result->create_enumerator(result);
356: while (e1->enumerate(e1, &ts1))
357: {
358: if (!e2->enumerate(e2, &ts2) || !ts1->equals(ts1, ts2))
359: {
360: charon->bus->alert(charon->bus, ALERT_TS_NARROWED,
361: local, result, this);
362: break;
363: }
364: }
365: e1->destroy(e1);
366: e2->destroy(e2);
367:
368: derived->destroy_offset(derived, offsetof(traffic_selector_t, destroy));
369: }
370:
371: /* remove any redundant traffic selectors in the list */
372: e1 = result->create_enumerator(result);
373: e2 = result->create_enumerator(result);
374: while (e1->enumerate(e1, &ts1))
375: {
376: while (e2->enumerate(e2, &ts2))
377: {
378: if (ts1 != ts2)
379: {
380: if (ts2->is_contained_in(ts2, ts1))
381: {
382: result->remove_at(result, e2);
383: ts2->destroy(ts2);
384: result->reset_enumerator(result, e1);
385: break;
386: }
387: if (ts1->is_contained_in(ts1, ts2))
388: {
389: result->remove_at(result, e1);
390: ts1->destroy(ts1);
391: break;
392: }
393: }
394: }
395: result->reset_enumerator(result, e2);
396: }
397: e1->destroy(e1);
398: e2->destroy(e2);
399:
400: return result;
401: }
402:
403: METHOD(child_cfg_t, get_updown, char*,
404: private_child_cfg_t *this)
405: {
406: return this->updown;
407: }
408:
409: /**
410: * Applies jitter to the rekey value. Returns the new rekey value.
411: * Note: The distribution of random values is not perfect, but it
412: * should get the job done.
413: */
414: static uint64_t apply_jitter(uint64_t rekey, uint64_t jitter)
415: {
416: if (jitter == 0)
417: {
418: return rekey;
419: }
420: jitter = (jitter == UINT64_MAX) ? jitter : jitter + 1;
421: return rekey - jitter * (random() / (RAND_MAX + 1.0));
422: }
423: #define APPLY_JITTER(l) l.rekey = apply_jitter(l.rekey, l.jitter)
424:
425: METHOD(child_cfg_t, get_lifetime, lifetime_cfg_t*,
426: private_child_cfg_t *this, bool jitter)
427: {
428: lifetime_cfg_t *lft = malloc_thing(lifetime_cfg_t);
429: memcpy(lft, &this->lifetime, sizeof(lifetime_cfg_t));
430: if (!jitter)
431: {
432: lft->time.jitter = lft->bytes.jitter = lft->packets.jitter = 0;
433: }
434: APPLY_JITTER(lft->time);
435: APPLY_JITTER(lft->bytes);
436: APPLY_JITTER(lft->packets);
437: return lft;
438: }
439:
440: METHOD(child_cfg_t, get_mode, ipsec_mode_t,
441: private_child_cfg_t *this)
442: {
443: return this->mode;
444: }
445:
446: METHOD(child_cfg_t, get_start_action, action_t,
447: private_child_cfg_t *this)
448: {
449: return this->start_action;
450: }
451:
452: METHOD(child_cfg_t, get_hw_offload, hw_offload_t,
453: private_child_cfg_t *this)
454: {
455: return this->hw_offload;
456: }
457:
458: METHOD(child_cfg_t, get_copy_dscp, dscp_copy_t,
459: private_child_cfg_t *this)
460: {
461: return this->copy_dscp;
462: }
463:
464: METHOD(child_cfg_t, get_dpd_action, action_t,
465: private_child_cfg_t *this)
466: {
467: return this->dpd_action;
468: }
469:
470: METHOD(child_cfg_t, get_close_action, action_t,
471: private_child_cfg_t *this)
472: {
473: return this->close_action;
474: }
475:
476: METHOD(child_cfg_t, get_dh_group, diffie_hellman_group_t,
477: private_child_cfg_t *this)
478: {
479: enumerator_t *enumerator;
480: proposal_t *proposal;
481: uint16_t dh_group = MODP_NONE;
482:
483: enumerator = this->proposals->create_enumerator(this->proposals);
484: while (enumerator->enumerate(enumerator, &proposal))
485: {
486: if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
487: {
488: break;
489: }
490: }
491: enumerator->destroy(enumerator);
492: return dh_group;
493: }
494:
495: METHOD(child_cfg_t, get_inactivity, uint32_t,
496: private_child_cfg_t *this)
497: {
498: return this->inactivity;
499: }
500:
501: METHOD(child_cfg_t, get_reqid, uint32_t,
502: private_child_cfg_t *this)
503: {
504: return this->reqid;
505: }
506:
507: METHOD(child_cfg_t, get_if_id, uint32_t,
508: private_child_cfg_t *this, bool inbound)
509: {
510: return inbound ? this->if_id_in : this->if_id_out;
511: }
512:
513: METHOD(child_cfg_t, get_mark, mark_t,
514: private_child_cfg_t *this, bool inbound)
515: {
516: return inbound ? this->mark_in : this->mark_out;
517: }
518:
519: METHOD(child_cfg_t, get_set_mark, mark_t,
520: private_child_cfg_t *this, bool inbound)
521: {
522: return inbound ? this->set_mark_in : this->set_mark_out;
523: }
524:
525: METHOD(child_cfg_t, get_tfc, uint32_t,
526: private_child_cfg_t *this)
527: {
528: return this->tfc;
529: }
530:
531: METHOD(child_cfg_t, get_manual_prio, uint32_t,
532: private_child_cfg_t *this)
533: {
534: return this->manual_prio;
535: }
536:
537: METHOD(child_cfg_t, get_interface, char*,
538: private_child_cfg_t *this)
539: {
540: return this->interface;
541: }
542:
543: METHOD(child_cfg_t, get_replay_window, uint32_t,
544: private_child_cfg_t *this)
545: {
546: return this->replay_window;
547: }
548:
549: METHOD(child_cfg_t, set_replay_window, void,
550: private_child_cfg_t *this, uint32_t replay_window)
551: {
552: this->replay_window = replay_window;
553: }
554:
555: #define LT_PART_EQUALS(a, b) ({ a.life == b.life && a.rekey == b.rekey && a.jitter == b.jitter; })
556: #define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); })
557:
558: METHOD(child_cfg_t, equals, bool,
559: private_child_cfg_t *this, child_cfg_t *other_pub)
560: {
561: private_child_cfg_t *other = (private_child_cfg_t*)other_pub;
562:
563: if (this == other)
564: {
565: return TRUE;
566: }
567: if (this->public.equals != other->public.equals)
568: {
569: return FALSE;
570: }
571: if (!this->proposals->equals_offset(this->proposals, other->proposals,
572: offsetof(proposal_t, equals)))
573: {
574: return FALSE;
575: }
576: if (!this->my_ts->equals_offset(this->my_ts, other->my_ts,
577: offsetof(traffic_selector_t, equals)))
578: {
579: return FALSE;
580: }
581: if (!this->other_ts->equals_offset(this->other_ts, other->other_ts,
582: offsetof(traffic_selector_t, equals)))
583: {
584: return FALSE;
585: }
586: return this->options == other->options &&
587: this->mode == other->mode &&
588: this->start_action == other->start_action &&
589: this->dpd_action == other->dpd_action &&
590: this->close_action == other->close_action &&
591: LIFETIME_EQUALS(this->lifetime, other->lifetime) &&
592: this->inactivity == other->inactivity &&
593: this->reqid == other->reqid &&
594: this->if_id_in == other->if_id_in &&
595: this->if_id_out == other->if_id_out &&
596: this->mark_in.value == other->mark_in.value &&
597: this->mark_in.mask == other->mark_in.mask &&
598: this->mark_out.value == other->mark_out.value &&
599: this->mark_out.mask == other->mark_out.mask &&
600: this->set_mark_in.value == other->set_mark_in.value &&
601: this->set_mark_in.mask == other->set_mark_in.mask &&
602: this->set_mark_out.value == other->set_mark_out.value &&
603: this->set_mark_out.mask == other->set_mark_out.mask &&
604: this->tfc == other->tfc &&
605: this->manual_prio == other->manual_prio &&
606: this->replay_window == other->replay_window &&
607: this->hw_offload == other->hw_offload &&
608: this->copy_dscp == other->copy_dscp &&
609: streq(this->updown, other->updown) &&
610: streq(this->interface, other->interface);
611: }
612:
613: METHOD(child_cfg_t, get_ref, child_cfg_t*,
614: private_child_cfg_t *this)
615: {
616: ref_get(&this->refcount);
617: return &this->public;
618: }
619:
620: METHOD(child_cfg_t, destroy, void,
621: private_child_cfg_t *this)
622: {
623: if (ref_put(&this->refcount))
624: {
625: this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
626: this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
627: this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
628: free(this->updown);
629: free(this->interface);
630: free(this->name);
631: free(this);
632: }
633: }
634:
635: /*
636: * Described in header-file
637: */
638: child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
639: {
640: private_child_cfg_t *this;
641:
642: INIT(this,
643: .public = {
644: .get_name = _get_name,
645: .add_traffic_selector = _add_traffic_selector,
646: .get_traffic_selectors = _get_traffic_selectors,
647: .add_proposal = _add_proposal,
648: .get_proposals = _get_proposals,
649: .select_proposal = _select_proposal,
650: .get_updown = _get_updown,
651: .get_mode = _get_mode,
652: .get_start_action = _get_start_action,
653: .get_dpd_action = _get_dpd_action,
654: .get_close_action = _get_close_action,
655: .get_lifetime = _get_lifetime,
656: .get_dh_group = _get_dh_group,
657: .get_inactivity = _get_inactivity,
658: .get_reqid = _get_reqid,
659: .get_if_id = _get_if_id,
660: .get_mark = _get_mark,
661: .get_set_mark = _get_set_mark,
662: .get_tfc = _get_tfc,
663: .get_manual_prio = _get_manual_prio,
664: .get_interface = _get_interface,
665: .get_replay_window = _get_replay_window,
666: .set_replay_window = _set_replay_window,
667: .has_option = _has_option,
668: .equals = _equals,
669: .get_ref = _get_ref,
670: .destroy = _destroy,
671: .get_hw_offload = _get_hw_offload,
672: .get_copy_dscp = _get_copy_dscp,
673: },
674: .name = strdup(name),
675: .options = data->options,
676: .updown = strdupnull(data->updown),
677: .reqid = data->reqid,
678: .if_id_in = data->if_id_in,
679: .if_id_out = data->if_id_out,
680: .mode = data->mode,
681: .start_action = data->start_action,
682: .dpd_action = data->dpd_action,
683: .close_action = data->close_action,
684: .mark_in = data->mark_in,
685: .mark_out = data->mark_out,
686: .set_mark_in = data->set_mark_in,
687: .set_mark_out = data->set_mark_out,
688: .lifetime = data->lifetime,
689: .inactivity = data->inactivity,
690: .tfc = data->tfc,
691: .manual_prio = data->priority,
692: .interface = strdupnull(data->interface),
693: .refcount = 1,
694: .proposals = linked_list_create(),
695: .my_ts = linked_list_create(),
696: .other_ts = linked_list_create(),
697: .replay_window = lib->settings->get_int(lib->settings,
698: "%s.replay_window", DEFAULT_REPLAY_WINDOW, lib->ns),
699: .hw_offload = data->hw_offload,
700: .copy_dscp = data->copy_dscp,
701: );
702:
703: return &this->public;
704: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>