Annotation of embedaddon/strongswan/src/libcharon/sa/child_sa.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2006-2019 Tobias Brunner
3: * Copyright (C) 2016 Andreas Steffen
4: * Copyright (C) 2005-2008 Martin Willi
5: * Copyright (C) 2006 Daniel Roethlisberger
6: * Copyright (C) 2005 Jan Hutter
7: * HSR Hochschule fuer Technik Rapperswil
8: *
9: * This program is free software; you can redistribute it and/or modify it
10: * under the terms of the GNU General Public License as published by the
11: * Free Software Foundation; either version 2 of the License, or (at your
12: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13: *
14: * This program is distributed in the hope that it will be useful, but
15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17: * for more details.
18: */
19:
20: #define _GNU_SOURCE
21: #include "child_sa.h"
22:
23: #include <stdio.h>
24: #include <string.h>
25: #include <time.h>
26:
27: #include <daemon.h>
28: #include <collections/array.h>
29:
30: ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
31: "CREATED",
32: "ROUTED",
33: "INSTALLING",
34: "INSTALLED",
35: "UPDATING",
36: "REKEYING",
37: "REKEYED",
38: "RETRYING",
39: "DELETING",
40: "DELETED",
41: "DESTROYING",
42: );
43:
44: ENUM_FLAGS(child_sa_outbound_state_names, CHILD_OUTBOUND_REGISTERED, CHILD_OUTBOUND_POLICIES,
45: "REGISTERED",
46: "SA",
47: "POLICIES",
48: );
49:
50: typedef struct private_child_sa_t private_child_sa_t;
51:
52: /**
53: * Private data of a child_sa_t object.
54: */
55: struct private_child_sa_t {
56: /**
57: * Public interface of child_sa_t.
58: */
59: child_sa_t public;
60:
61: /**
62: * address of us
63: */
64: host_t *my_addr;
65:
66: /**
67: * address of remote
68: */
69: host_t *other_addr;
70:
71: /**
72: * our actually used SPI, 0 if unused
73: */
74: uint32_t my_spi;
75:
76: /**
77: * others used SPI, 0 if unused
78: */
79: uint32_t other_spi;
80:
81: /**
82: * our Compression Parameter Index (CPI) used, 0 if unused
83: */
84: uint16_t my_cpi;
85:
86: /**
87: * others Compression Parameter Index (CPI) used, 0 if unused
88: */
89: uint16_t other_cpi;
90:
91: /**
92: * Array for local traffic selectors
93: */
94: array_t *my_ts;
95:
96: /**
97: * Array for remote traffic selectors
98: */
99: array_t *other_ts;
100:
101: /**
102: * Outbound encryption key cached during a rekeying
103: */
104: chunk_t encr_r;
105:
106: /**
107: * Outbound integrity key cached during a rekeying
108: */
109: chunk_t integ_r;
110:
111: /**
112: * Whether the outbound SA has only been registered yet during a rekeying
113: */
114: child_sa_outbound_state_t outbound_state;
115:
116: /**
117: * Whether the peer supports TFCv3
118: */
119: bool tfcv3;
120:
121: /**
122: * The outbound SPI of the CHILD_SA that replaced this one during a rekeying
123: */
124: uint32_t rekey_spi;
125:
126: /**
127: * Protocol used to protect this SA, ESP|AH
128: */
129: protocol_id_t protocol;
130:
131: /**
132: * reqid used for this child_sa
133: */
134: uint32_t reqid;
135:
136: /**
137: * Did we allocate/confirm and must release the reqid?
138: */
139: bool reqid_allocated;
140:
141: /**
142: * Is the reqid statically configured
143: */
144: bool static_reqid;
145:
146: /**
147: * Unique CHILD_SA identifier
148: */
149: uint32_t unique_id;
150:
151: /**
152: * Whether FWD policies in the outbound direction should be installed
153: */
154: bool policies_fwd_out;
155:
156: /**
157: * Inbound interface ID
158: */
159: uint32_t if_id_in;
160:
161: /**
162: * Outbound interface ID
163: */
164: uint32_t if_id_out;
165:
166: /**
167: * inbound mark used for this child_sa
168: */
169: mark_t mark_in;
170:
171: /**
172: * outbound mark used for this child_sa
173: */
174: mark_t mark_out;
175:
176: /**
177: * absolute time when rekeying is scheduled
178: */
179: time_t rekey_time;
180:
181: /**
182: * absolute time when the SA expires
183: */
184: time_t expire_time;
185:
186: /**
187: * absolute time when SA has been installed
188: */
189: time_t install_time;
190:
191: /**
192: * state of the CHILD_SA
193: */
194: child_sa_state_t state;
195:
196: /**
197: * TRUE if this CHILD_SA is used to install trap policies
198: */
199: bool trap;
200:
201: /**
202: * Specifies if UDP encapsulation is enabled (NAT traversal)
203: */
204: bool encap;
205:
206: /**
207: * Specifies the IPComp transform used (IPCOMP_NONE if disabled)
208: */
209: ipcomp_transform_t ipcomp;
210:
211: /**
212: * mode this SA uses, tunnel/transport
213: */
214: ipsec_mode_t mode;
215:
216: /**
217: * Action to enforce if peer closes the CHILD_SA
218: */
219: action_t close_action;
220:
221: /**
222: * Action to enforce if peer is considered dead
223: */
224: action_t dpd_action;
225:
226: /**
227: * selected proposal
228: */
229: proposal_t *proposal;
230:
231: /**
232: * config used to create this child
233: */
234: child_cfg_t *config;
235:
236: /**
237: * time of last use in seconds (inbound)
238: */
239: time_t my_usetime;
240:
241: /**
242: * time of last use in seconds (outbound)
243: */
244: time_t other_usetime;
245:
246: /**
247: * last number of inbound bytes
248: */
249: uint64_t my_usebytes;
250:
251: /**
252: * last number of outbound bytes
253: */
254: uint64_t other_usebytes;
255:
256: /**
257: * last number of inbound packets
258: */
259: uint64_t my_usepackets;
260:
261: /**
262: * last number of outbound bytes
263: */
264: uint64_t other_usepackets;
265: };
266:
267: /**
268: * Convert an IKEv2 specific protocol identifier to the IP protocol identifier
269: */
270: static inline uint8_t proto_ike2ip(protocol_id_t protocol)
271: {
272: switch (protocol)
273: {
274: case PROTO_ESP:
275: return IPPROTO_ESP;
276: case PROTO_AH:
277: return IPPROTO_AH;
278: default:
279: return protocol;
280: }
281: }
282:
283: /**
284: * Returns the mark to use on the inbound SA
285: */
286: static inline mark_t mark_in_sa(private_child_sa_t *this)
287: {
288: if (this->config->has_option(this->config, OPT_MARK_IN_SA))
289: {
290: return this->mark_in;
291: }
292: return (mark_t){};
293: }
294:
295: METHOD(child_sa_t, get_name, char*,
296: private_child_sa_t *this)
297: {
298: return this->config->get_name(this->config);
299: }
300:
301: METHOD(child_sa_t, get_reqid, uint32_t,
302: private_child_sa_t *this)
303: {
304: return this->reqid;
305: }
306:
307: METHOD(child_sa_t, get_unique_id, uint32_t,
308: private_child_sa_t *this)
309: {
310: return this->unique_id;
311: }
312:
313: METHOD(child_sa_t, get_config, child_cfg_t*,
314: private_child_sa_t *this)
315: {
316: return this->config;
317: }
318:
319: METHOD(child_sa_t, set_state, void,
320: private_child_sa_t *this, child_sa_state_t state)
321: {
322: if (this->state != state)
323: {
324: DBG2(DBG_CHD, "CHILD_SA %s{%d} state change: %N => %N",
325: get_name(this), this->unique_id,
326: child_sa_state_names, this->state,
327: child_sa_state_names, state);
328: charon->bus->child_state_change(charon->bus, &this->public, state);
329: this->state = state;
330: }
331: }
332:
333: METHOD(child_sa_t, get_state, child_sa_state_t,
334: private_child_sa_t *this)
335: {
336: return this->state;
337: }
338:
339: METHOD(child_sa_t, get_outbound_state, child_sa_outbound_state_t,
340: private_child_sa_t *this)
341: {
342: return this->outbound_state;
343: }
344:
345: METHOD(child_sa_t, get_spi, uint32_t,
346: private_child_sa_t *this, bool inbound)
347: {
348: return inbound ? this->my_spi : this->other_spi;
349: }
350:
351: METHOD(child_sa_t, get_cpi, uint16_t,
352: private_child_sa_t *this, bool inbound)
353: {
354: return inbound ? this->my_cpi : this->other_cpi;
355: }
356:
357: METHOD(child_sa_t, get_protocol, protocol_id_t,
358: private_child_sa_t *this)
359: {
360: return this->protocol;
361: }
362:
363: METHOD(child_sa_t, set_protocol, void,
364: private_child_sa_t *this, protocol_id_t protocol)
365: {
366: this->protocol = protocol;
367: }
368:
369: METHOD(child_sa_t, get_mode, ipsec_mode_t,
370: private_child_sa_t *this)
371: {
372: return this->mode;
373: }
374:
375: METHOD(child_sa_t, set_mode, void,
376: private_child_sa_t *this, ipsec_mode_t mode)
377: {
378: this->mode = mode;
379: }
380:
381: METHOD(child_sa_t, has_encap, bool,
382: private_child_sa_t *this)
383: {
384: return this->encap;
385: }
386:
387: METHOD(child_sa_t, get_ipcomp, ipcomp_transform_t,
388: private_child_sa_t *this)
389: {
390: return this->ipcomp;
391: }
392:
393: METHOD(child_sa_t, set_ipcomp, void,
394: private_child_sa_t *this, ipcomp_transform_t ipcomp)
395: {
396: this->ipcomp = ipcomp;
397: }
398:
399: METHOD(child_sa_t, set_close_action, void,
400: private_child_sa_t *this, action_t action)
401: {
402: this->close_action = action;
403: }
404:
405: METHOD(child_sa_t, get_close_action, action_t,
406: private_child_sa_t *this)
407: {
408: return this->close_action;
409: }
410:
411: METHOD(child_sa_t, set_dpd_action, void,
412: private_child_sa_t *this, action_t action)
413: {
414: this->dpd_action = action;
415: }
416:
417: METHOD(child_sa_t, get_dpd_action, action_t,
418: private_child_sa_t *this)
419: {
420: return this->dpd_action;
421: }
422:
423: METHOD(child_sa_t, get_proposal, proposal_t*,
424: private_child_sa_t *this)
425: {
426: return this->proposal;
427: }
428:
429: METHOD(child_sa_t, set_proposal, void,
430: private_child_sa_t *this, proposal_t *proposal)
431: {
432: this->proposal = proposal->clone(proposal, 0);
433: }
434:
435: METHOD(child_sa_t, create_ts_enumerator, enumerator_t*,
436: private_child_sa_t *this, bool local)
437: {
438: if (local)
439: {
440: return array_create_enumerator(this->my_ts);
441: }
442: return array_create_enumerator(this->other_ts);
443: }
444:
445: typedef struct policy_enumerator_t policy_enumerator_t;
446:
447: /**
448: * Private policy enumerator
449: */
450: struct policy_enumerator_t {
451: /** implements enumerator_t */
452: enumerator_t public;
453: /** enumerator over own TS */
454: enumerator_t *mine;
455: /** enumerator over others TS */
456: enumerator_t *other;
457: /** array of others TS, to recreate enumerator */
458: array_t *array;
459: /** currently enumerating TS for "me" side */
460: traffic_selector_t *ts;
461: };
462:
463: METHOD(enumerator_t, policy_enumerate, bool,
464: policy_enumerator_t *this, va_list args)
465: {
466: traffic_selector_t *other_ts, **my_out, **other_out;
467:
468: VA_ARGS_VGET(args, my_out, other_out);
469:
470: while (this->ts || this->mine->enumerate(this->mine, &this->ts))
471: {
472: if (!this->other->enumerate(this->other, &other_ts))
473: { /* end of others list, restart with new of mine */
474: this->other->destroy(this->other);
475: this->other = array_create_enumerator(this->array);
476: this->ts = NULL;
477: continue;
478: }
479: if (this->ts->get_type(this->ts) != other_ts->get_type(other_ts))
480: { /* family mismatch */
481: continue;
482: }
483: if (this->ts->get_protocol(this->ts) &&
484: other_ts->get_protocol(other_ts) &&
485: this->ts->get_protocol(this->ts) != other_ts->get_protocol(other_ts))
486: { /* protocol mismatch */
487: continue;
488: }
489: if (my_out)
490: {
491: *my_out = this->ts;
492: }
493: if (other_out)
494: {
495: *other_out = other_ts;
496: }
497: return TRUE;
498: }
499: return FALSE;
500: }
501:
502: METHOD(enumerator_t, policy_destroy, void,
503: policy_enumerator_t *this)
504: {
505: this->mine->destroy(this->mine);
506: this->other->destroy(this->other);
507: free(this);
508: }
509:
510: METHOD(child_sa_t, create_policy_enumerator, enumerator_t*,
511: private_child_sa_t *this)
512: {
513: policy_enumerator_t *e;
514:
515: INIT(e,
516: .public = {
517: .enumerate = enumerator_enumerate_default,
518: .venumerate = _policy_enumerate,
519: .destroy = _policy_destroy,
520: },
521: .mine = array_create_enumerator(this->my_ts),
522: .other = array_create_enumerator(this->other_ts),
523: .array = this->other_ts,
524: .ts = NULL,
525: );
526:
527: return &e->public;
528: }
529:
530: /**
531: * update the cached usebytes
532: * returns SUCCESS if the usebytes have changed, FAILED if not or no SPIs
533: * are available, and NOT_SUPPORTED if the kernel interface does not support
534: * querying the usebytes.
535: */
536: static status_t update_usebytes(private_child_sa_t *this, bool inbound)
537: {
538: status_t status = FAILED;
539: uint64_t bytes, packets;
540: time_t time;
541:
542: if (inbound)
543: {
544: if (this->my_spi)
545: {
546: kernel_ipsec_sa_id_t id = {
547: .src = this->other_addr,
548: .dst = this->my_addr,
549: .spi = this->my_spi,
550: .proto = proto_ike2ip(this->protocol),
551: .mark = mark_in_sa(this),
552: .if_id = this->if_id_in,
553: };
554: kernel_ipsec_query_sa_t query = {};
555:
556: status = charon->kernel->query_sa(charon->kernel, &id, &query,
557: &bytes, &packets, &time);
558: if (status == SUCCESS)
559: {
560: if (bytes > this->my_usebytes)
561: {
562: this->my_usebytes = bytes;
563: this->my_usepackets = packets;
564: if (time)
565: {
566: this->my_usetime = time;
567: }
568: }
569: else
570: {
571: status = FAILED;
572: }
573: }
574: }
575: }
576: else
577: {
578: if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
579: {
580: kernel_ipsec_sa_id_t id = {
581: .src = this->my_addr,
582: .dst = this->other_addr,
583: .spi = this->other_spi,
584: .proto = proto_ike2ip(this->protocol),
585: .mark = this->mark_out,
586: .if_id = this->if_id_out,
587: };
588: kernel_ipsec_query_sa_t query = {};
589:
590: status = charon->kernel->query_sa(charon->kernel, &id, &query,
591: &bytes, &packets, &time);
592: if (status == SUCCESS)
593: {
594: if (bytes > this->other_usebytes)
595: {
596: this->other_usebytes = bytes;
597: this->other_usepackets = packets;
598: if (time)
599: {
600: this->other_usetime = time;
601: }
602: }
603: else
604: {
605: status = FAILED;
606: }
607: }
608: }
609: }
610: return status;
611: }
612:
613: /**
614: * updates the cached usetime
615: */
616: static bool update_usetime(private_child_sa_t *this, bool inbound)
617: {
618: enumerator_t *enumerator;
619: traffic_selector_t *my_ts, *other_ts;
620: time_t last_use = 0;
621:
622: enumerator = create_policy_enumerator(this);
623: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
624: {
625: time_t in, out, fwd;
626:
627: if (inbound)
628: {
629: kernel_ipsec_policy_id_t id = {
630: .dir = POLICY_IN,
631: .src_ts = other_ts,
632: .dst_ts = my_ts,
633: .mark = this->mark_in,
634: .if_id = this->if_id_in,
635: };
636: kernel_ipsec_query_policy_t query = {};
637:
638: if (charon->kernel->query_policy(charon->kernel, &id, &query,
639: &in) == SUCCESS)
640: {
641: last_use = max(last_use, in);
642: }
643: if (this->mode != MODE_TRANSPORT)
644: {
645: id.dir = POLICY_FWD;
646: if (charon->kernel->query_policy(charon->kernel, &id, &query,
647: &fwd) == SUCCESS)
648: {
649: last_use = max(last_use, fwd);
650: }
651: }
652: }
653: else
654: {
655: kernel_ipsec_policy_id_t id = {
656: .dir = POLICY_OUT,
657: .src_ts = my_ts,
658: .dst_ts = other_ts,
659: .mark = this->mark_out,
660: .if_id = this->if_id_out,
661: .interface = this->config->get_interface(this->config),
662: };
663: kernel_ipsec_query_policy_t query = {};
664:
665: if (charon->kernel->query_policy(charon->kernel, &id, &query,
666: &out) == SUCCESS)
667: {
668: last_use = max(last_use, out);
669: }
670: }
671: }
672: enumerator->destroy(enumerator);
673:
674: if (last_use == 0)
675: {
676: return FALSE;
677: }
678: if (inbound)
679: {
680: this->my_usetime = last_use;
681: }
682: else
683: {
684: this->other_usetime = last_use;
685: }
686: return TRUE;
687: }
688:
689: METHOD(child_sa_t, get_usestats, void,
690: private_child_sa_t *this, bool inbound,
691: time_t *time, uint64_t *bytes, uint64_t *packets)
692: {
693: if ((!bytes && !packets) || update_usebytes(this, inbound) != FAILED)
694: {
695: /* there was traffic since last update or the kernel interface
696: * does not support querying the number of usebytes.
697: */
698: if (time)
699: {
700: if (!update_usetime(this, inbound) && !bytes && !packets)
701: {
702: /* if policy query did not yield a usetime, query SAs instead */
703: update_usebytes(this, inbound);
704: }
705: }
706: }
707: if (time)
708: {
709: *time = inbound ? this->my_usetime : this->other_usetime;
710: }
711: if (bytes)
712: {
713: *bytes = inbound ? this->my_usebytes : this->other_usebytes;
714: }
715: if (packets)
716: {
717: *packets = inbound ? this->my_usepackets : this->other_usepackets;
718: }
719: }
720:
721: METHOD(child_sa_t, get_mark, mark_t,
722: private_child_sa_t *this, bool inbound)
723: {
724: return inbound ? this->mark_in : this->mark_out;
725: }
726:
727: METHOD(child_sa_t, get_if_id, uint32_t,
728: private_child_sa_t *this, bool inbound)
729: {
730: return inbound ? this->if_id_in : this->if_id_out;
731: }
732:
733: METHOD(child_sa_t, get_lifetime, time_t,
734: private_child_sa_t *this, bool hard)
735: {
736: return hard ? this->expire_time : this->rekey_time;
737: }
738:
739: METHOD(child_sa_t, get_installtime, time_t,
740: private_child_sa_t *this)
741: {
742: return this->install_time;
743: }
744:
745: METHOD(child_sa_t, alloc_spi, uint32_t,
746: private_child_sa_t *this, protocol_id_t protocol)
747: {
748: if (charon->kernel->get_spi(charon->kernel, this->other_addr, this->my_addr,
749: proto_ike2ip(protocol), &this->my_spi) == SUCCESS)
750: {
751: /* if we allocate a SPI, but then are unable to establish the SA, we
752: * need to know the protocol family to delete the partial SA */
753: this->protocol = protocol;
754: return this->my_spi;
755: }
756: return 0;
757: }
758:
759: METHOD(child_sa_t, alloc_cpi, uint16_t,
760: private_child_sa_t *this)
761: {
762: if (charon->kernel->get_cpi(charon->kernel, this->other_addr, this->my_addr,
763: &this->my_cpi) == SUCCESS)
764: {
765: return this->my_cpi;
766: }
767: return 0;
768: }
769:
770: /**
771: * Install the given SA in the kernel
772: */
773: static status_t install_internal(private_child_sa_t *this, chunk_t encr,
774: chunk_t integ, uint32_t spi, uint16_t cpi, bool initiator, bool inbound,
775: bool tfcv3)
776: {
777: uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
778: uint16_t esn = NO_EXT_SEQ_NUMBERS;
779: linked_list_t *my_ts, *other_ts, *src_ts, *dst_ts;
780: time_t now;
781: kernel_ipsec_sa_id_t id;
782: kernel_ipsec_add_sa_t sa;
783: lifetime_cfg_t *lifetime;
784: uint32_t tfc = 0;
785: host_t *src, *dst;
786: status_t status;
787: bool update = FALSE;
788:
789: /* BEET requires the bound address from the traffic selectors */
790: my_ts = linked_list_create_from_enumerator(
791: array_create_enumerator(this->my_ts));
792: other_ts = linked_list_create_from_enumerator(
793: array_create_enumerator(this->other_ts));
794:
795: /* now we have to decide which spi to use. Use self allocated, if "in",
796: * or the one in the proposal, if not "in" (others). Additionally,
797: * source and dest host switch depending on the role */
798: if (inbound)
799: {
800: dst = this->my_addr;
801: src = this->other_addr;
802: if (this->my_spi == spi)
803: { /* alloc_spi has been called, do an SA update */
804: update = TRUE;
805: }
806: this->my_spi = spi;
807: this->my_cpi = cpi;
808: dst_ts = my_ts;
809: src_ts = other_ts;
810: }
811: else
812: {
813: src = this->my_addr;
814: dst = this->other_addr;
815: this->other_spi = spi;
816: this->other_cpi = cpi;
817: src_ts = my_ts;
818: dst_ts = other_ts;
819:
820: if (tfcv3)
821: {
822: tfc = this->config->get_tfc(this->config);
823: }
824: this->outbound_state |= CHILD_OUTBOUND_SA;
825: }
826:
827: DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
828: protocol_id_names, this->protocol);
829:
830: /* send SA down to the kernel */
831: DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
832:
833: this->proposal->get_algorithm(this->proposal, ENCRYPTION_ALGORITHM,
834: &enc_alg, &size);
835: this->proposal->get_algorithm(this->proposal, INTEGRITY_ALGORITHM,
836: &int_alg, &size);
837: this->proposal->get_algorithm(this->proposal, EXTENDED_SEQUENCE_NUMBERS,
838: &esn, NULL);
839:
840: if (int_alg == AUTH_HMAC_SHA2_256_128 &&
841: this->config->has_option(this->config, OPT_SHA256_96))
842: {
843: DBG2(DBG_CHD, " using %N with 96-bit truncation",
844: integrity_algorithm_names, int_alg);
845: int_alg = AUTH_HMAC_SHA2_256_96;
846: }
847:
848: if (!this->reqid_allocated && !this->static_reqid)
849: {
850: status = charon->kernel->alloc_reqid(charon->kernel, my_ts, other_ts,
851: this->mark_in, this->mark_out, this->if_id_in,
852: this->if_id_out, &this->reqid);
853: if (status != SUCCESS)
854: {
855: my_ts->destroy(my_ts);
856: other_ts->destroy(other_ts);
857: return status;
858: }
859: this->reqid_allocated = TRUE;
860: }
861:
862: lifetime = this->config->get_lifetime(this->config, TRUE);
863:
864: now = time_monotonic(NULL);
865: if (lifetime->time.rekey)
866: {
867: if (this->rekey_time)
868: {
869: this->rekey_time = min(this->rekey_time, now + lifetime->time.rekey);
870: }
871: else
872: {
873: this->rekey_time = now + lifetime->time.rekey;
874: }
875: }
876: if (lifetime->time.life)
877: {
878: this->expire_time = now + lifetime->time.life;
879: }
880:
881: if (!lifetime->time.jitter && !inbound)
882: { /* avoid triggering multiple rekey events */
883: lifetime->time.rekey = 0;
884: }
885:
886: id = (kernel_ipsec_sa_id_t){
887: .src = src,
888: .dst = dst,
889: .spi = spi,
890: .proto = proto_ike2ip(this->protocol),
891: .mark = inbound ? mark_in_sa(this) : this->mark_out,
892: .if_id = inbound ? this->if_id_in : this->if_id_out,
893: };
894: sa = (kernel_ipsec_add_sa_t){
895: .reqid = this->reqid,
896: .mode = this->mode,
897: .src_ts = src_ts,
898: .dst_ts = dst_ts,
899: .interface = inbound ? NULL : this->config->get_interface(this->config),
900: .lifetime = lifetime,
901: .enc_alg = enc_alg,
902: .enc_key = encr,
903: .int_alg = int_alg,
904: .int_key = integ,
905: .replay_window = this->config->get_replay_window(this->config),
906: .tfc = tfc,
907: .ipcomp = this->ipcomp,
908: .cpi = cpi,
909: .encap = this->encap,
910: .hw_offload = this->config->get_hw_offload(this->config),
911: .mark = this->config->get_set_mark(this->config, inbound),
912: .esn = esn,
913: .copy_df = !this->config->has_option(this->config, OPT_NO_COPY_DF),
914: .copy_ecn = !this->config->has_option(this->config, OPT_NO_COPY_ECN),
915: .copy_dscp = this->config->get_copy_dscp(this->config),
916: .initiator = initiator,
917: .inbound = inbound,
918: .update = update,
919: };
920:
921: if (sa.mark.value == MARK_SAME)
922: {
923: sa.mark.value = inbound ? this->mark_in.value : this->mark_out.value;
924: }
925:
926: status = charon->kernel->add_sa(charon->kernel, &id, &sa);
927:
928: my_ts->destroy(my_ts);
929: other_ts->destroy(other_ts);
930: free(lifetime);
931:
932: return status;
933: }
934:
935: METHOD(child_sa_t, install, status_t,
936: private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
937: uint16_t cpi, bool initiator, bool inbound, bool tfcv3)
938: {
939: return install_internal(this, encr, integ, spi, cpi, initiator, inbound,
940: tfcv3);
941: }
942:
943: /**
944: * Check kernel interface if policy updates are required
945: */
946: static bool require_policy_update()
947: {
948: kernel_feature_t f;
949:
950: f = charon->kernel->get_features(charon->kernel);
951: return !(f & KERNEL_NO_POLICY_UPDATES);
952: }
953:
954: /**
955: * Prepare SA config to install/delete policies
956: */
957: static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa,
958: ipsec_sa_cfg_t *other_sa)
959: {
960: enumerator_t *enumerator;
961:
962: *my_sa = (ipsec_sa_cfg_t){
963: .mode = this->mode,
964: .reqid = this->reqid,
965: .ipcomp = {
966: .transform = this->ipcomp,
967: },
968: };
969: *other_sa = *my_sa;
970:
971: my_sa->ipcomp.cpi = this->my_cpi;
972: other_sa->ipcomp.cpi = this->other_cpi;
973:
974: if (this->protocol == PROTO_ESP)
975: {
976: my_sa->esp.use = TRUE;
977: my_sa->esp.spi = this->my_spi;
978: other_sa->esp.use = TRUE;
979: other_sa->esp.spi = this->other_spi;
980: }
981: else
982: {
983: my_sa->ah.use = TRUE;
984: my_sa->ah.spi = this->my_spi;
985: other_sa->ah.use = TRUE;
986: other_sa->ah.spi = this->other_spi;
987: }
988:
989: enumerator = create_policy_enumerator(this);
990: while (enumerator->enumerate(enumerator, NULL, NULL))
991: {
992: my_sa->policy_count++;
993: other_sa->policy_count++;
994: }
995: enumerator->destroy(enumerator);
996: }
997:
998: /**
999: * Install inbound policies: in, fwd
1000: */
1001: static status_t install_policies_inbound(private_child_sa_t *this,
1002: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
1003: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
1004: ipsec_sa_cfg_t *other_sa, policy_type_t type,
1005: policy_priority_t priority, uint32_t manual_prio)
1006: {
1007: kernel_ipsec_policy_id_t in_id = {
1008: .dir = POLICY_IN,
1009: .src_ts = other_ts,
1010: .dst_ts = my_ts,
1011: .mark = this->mark_in,
1012: .if_id = this->if_id_in,
1013: };
1014: kernel_ipsec_manage_policy_t in_policy = {
1015: .type = type,
1016: .prio = priority,
1017: .manual_prio = manual_prio,
1018: .src = other_addr,
1019: .dst = my_addr,
1020: .sa = my_sa,
1021: };
1022: status_t status = SUCCESS;
1023:
1024: status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
1025: if (this->mode != MODE_TRANSPORT)
1026: {
1027: in_id.dir = POLICY_FWD;
1028: status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
1029: }
1030: return status;
1031: }
1032:
1033: /**
1034: * Install outbound policies: out, [fwd]
1035: */
1036: static status_t install_policies_outbound(private_child_sa_t *this,
1037: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
1038: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
1039: ipsec_sa_cfg_t *other_sa, policy_type_t type,
1040: policy_priority_t priority, uint32_t manual_prio)
1041: {
1042: kernel_ipsec_policy_id_t out_id = {
1043: .dir = POLICY_OUT,
1044: .src_ts = my_ts,
1045: .dst_ts = other_ts,
1046: .mark = this->mark_out,
1047: .if_id = this->if_id_out,
1048: .interface = this->config->get_interface(this->config),
1049: };
1050: kernel_ipsec_manage_policy_t out_policy = {
1051: .type = type,
1052: .prio = priority,
1053: .manual_prio = manual_prio,
1054: .src = my_addr,
1055: .dst = other_addr,
1056: .sa = other_sa,
1057: };
1058: status_t status = SUCCESS;
1059:
1060: status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy);
1061:
1062: if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
1063: {
1064: /* install an "outbound" FWD policy in case there is a drop policy
1065: * matching outbound forwarded traffic, to allow another tunnel to use
1066: * the reversed subnets and do the same we don't set a reqid (this also
1067: * allows the kernel backend to distinguish between the two types of
1068: * FWD policies). To avoid problems with symmetrically overlapping
1069: * policies of two SAs we install them with reduced priority. As they
1070: * basically act as bypass policies for drop policies we use a higher
1071: * priority than is used for them. */
1072: out_id.dir = POLICY_FWD;
1073: other_sa->reqid = 0;
1074: if (priority == POLICY_PRIORITY_DEFAULT)
1075: {
1076: out_policy.prio = POLICY_PRIORITY_ROUTED;
1077: }
1078: status |= charon->kernel->add_policy(charon->kernel, &out_id,
1079: &out_policy);
1080: /* reset the reqid for any other further policies */
1081: other_sa->reqid = this->reqid;
1082: }
1083: return status;
1084: }
1085:
1086: /**
1087: * Install all policies
1088: */
1089: static status_t install_policies_internal(private_child_sa_t *this,
1090: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
1091: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
1092: ipsec_sa_cfg_t *other_sa, policy_type_t type,
1093: policy_priority_t priority, uint32_t manual_prio, bool outbound)
1094: {
1095: status_t status = SUCCESS;
1096:
1097: status |= install_policies_inbound(this, my_addr, other_addr, my_ts,
1098: other_ts, my_sa, other_sa, type, priority, manual_prio);
1099: if (outbound)
1100: {
1101: status |= install_policies_outbound(this, my_addr, other_addr, my_ts,
1102: other_ts, my_sa, other_sa, type, priority, manual_prio);
1103: }
1104: return status;
1105: }
1106:
1107: /**
1108: * Delete inbound policies: in, fwd
1109: */
1110: static void del_policies_inbound(private_child_sa_t *this,
1111: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
1112: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
1113: ipsec_sa_cfg_t *other_sa, policy_type_t type,
1114: policy_priority_t priority, uint32_t manual_prio)
1115: {
1116: kernel_ipsec_policy_id_t in_id = {
1117: .dir = POLICY_IN,
1118: .src_ts = other_ts,
1119: .dst_ts = my_ts,
1120: .mark = this->mark_in,
1121: .if_id = this->if_id_in,
1122: };
1123: kernel_ipsec_manage_policy_t in_policy = {
1124: .type = type,
1125: .prio = priority,
1126: .manual_prio = manual_prio,
1127: .src = other_addr,
1128: .dst = my_addr,
1129: .sa = my_sa,
1130: };
1131:
1132: charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
1133:
1134: if (this->mode != MODE_TRANSPORT)
1135: {
1136: in_id.dir = POLICY_FWD;
1137: charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
1138: }
1139: }
1140:
1141: /**
1142: * Delete outbound policies: out, [fwd]
1143: */
1144: static void del_policies_outbound(private_child_sa_t *this,
1145: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
1146: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
1147: ipsec_sa_cfg_t *other_sa, policy_type_t type,
1148: policy_priority_t priority, uint32_t manual_prio)
1149: {
1150: kernel_ipsec_policy_id_t out_id = {
1151: .dir = POLICY_OUT,
1152: .src_ts = my_ts,
1153: .dst_ts = other_ts,
1154: .mark = this->mark_out,
1155: .if_id = this->if_id_out,
1156: .interface = this->config->get_interface(this->config),
1157: };
1158: kernel_ipsec_manage_policy_t out_policy = {
1159: .type = type,
1160: .prio = priority,
1161: .manual_prio = manual_prio,
1162: .src = my_addr,
1163: .dst = other_addr,
1164: .sa = other_sa,
1165: };
1166:
1167: charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
1168:
1169: if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
1170: {
1171: out_id.dir = POLICY_FWD;
1172: other_sa->reqid = 0;
1173: if (priority == POLICY_PRIORITY_DEFAULT)
1174: {
1175: out_policy.prio = POLICY_PRIORITY_ROUTED;
1176: }
1177: charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
1178: other_sa->reqid = this->reqid;
1179: }
1180: }
1181:
1182: /**
1183: * Delete in- and outbound policies
1184: */
1185: static void del_policies_internal(private_child_sa_t *this,
1186: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
1187: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
1188: ipsec_sa_cfg_t *other_sa, policy_type_t type,
1189: policy_priority_t priority, uint32_t manual_prio, bool outbound)
1190: {
1191: if (outbound)
1192: {
1193: del_policies_outbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
1194: other_sa, type, priority, manual_prio);
1195: }
1196: del_policies_inbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
1197: other_sa, type, priority, manual_prio);
1198: }
1199:
1200: METHOD(child_sa_t, set_policies, void,
1201: private_child_sa_t *this, linked_list_t *my_ts_list,
1202: linked_list_t *other_ts_list)
1203: {
1204: enumerator_t *enumerator;
1205: traffic_selector_t *my_ts, *other_ts;
1206:
1207: if (array_count(this->my_ts))
1208: {
1209: array_destroy_offset(this->my_ts,
1210: offsetof(traffic_selector_t, destroy));
1211: this->my_ts = array_create(0, 0);
1212: }
1213: enumerator = my_ts_list->create_enumerator(my_ts_list);
1214: while (enumerator->enumerate(enumerator, &my_ts))
1215: {
1216: array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts));
1217: }
1218: enumerator->destroy(enumerator);
1219: array_sort(this->my_ts, (void*)traffic_selector_cmp, NULL);
1220:
1221: if (array_count(this->other_ts))
1222: {
1223: array_destroy_offset(this->other_ts,
1224: offsetof(traffic_selector_t, destroy));
1225: this->other_ts = array_create(0, 0);
1226: }
1227: enumerator = other_ts_list->create_enumerator(other_ts_list);
1228: while (enumerator->enumerate(enumerator, &other_ts))
1229: {
1230: array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts));
1231: }
1232: enumerator->destroy(enumerator);
1233: array_sort(this->other_ts, (void*)traffic_selector_cmp, NULL);
1234: }
1235:
1236: METHOD(child_sa_t, install_policies, status_t,
1237: private_child_sa_t *this)
1238: {
1239: enumerator_t *enumerator;
1240: linked_list_t *my_ts_list, *other_ts_list;
1241: traffic_selector_t *my_ts, *other_ts;
1242: status_t status = SUCCESS;
1243: bool install_outbound = FALSE;
1244:
1245: if (!this->reqid_allocated && !this->static_reqid)
1246: {
1247: my_ts_list = linked_list_create_from_enumerator(
1248: array_create_enumerator(this->my_ts));
1249: other_ts_list = linked_list_create_from_enumerator(
1250: array_create_enumerator(this->other_ts));
1251: status = charon->kernel->alloc_reqid(
1252: charon->kernel, my_ts_list, other_ts_list,
1253: this->mark_in, this->mark_out, this->if_id_in,
1254: this->if_id_out, &this->reqid);
1255: my_ts_list->destroy(my_ts_list);
1256: other_ts_list->destroy(other_ts_list);
1257: if (status != SUCCESS)
1258: {
1259: return status;
1260: }
1261: this->reqid_allocated = TRUE;
1262: }
1263:
1264: if (!(this->outbound_state & CHILD_OUTBOUND_REGISTERED))
1265: {
1266: install_outbound = TRUE;
1267: this->outbound_state |= CHILD_OUTBOUND_POLICIES;
1268: }
1269:
1270: if (!this->config->has_option(this->config, OPT_NO_POLICIES))
1271: {
1272: policy_priority_t priority;
1273: ipsec_sa_cfg_t my_sa, other_sa;
1274: uint32_t manual_prio;
1275:
1276: prepare_sa_cfg(this, &my_sa, &other_sa);
1277: manual_prio = this->config->get_manual_prio(this->config);
1278:
1279: /* if we're not in state CHILD_INSTALLING (i.e. if there is no SAD
1280: * entry) we install a trap policy */
1281: this->trap = this->state == CHILD_CREATED;
1282: priority = this->trap ? POLICY_PRIORITY_ROUTED
1283: : POLICY_PRIORITY_DEFAULT;
1284:
1285: /* enumerate pairs of traffic selectors */
1286: enumerator = create_policy_enumerator(this);
1287: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
1288: {
1289: status |= install_policies_internal(this, this->my_addr,
1290: this->other_addr, my_ts, other_ts,
1291: &my_sa, &other_sa, POLICY_IPSEC, priority,
1292: manual_prio, install_outbound);
1293: if (status != SUCCESS)
1294: {
1295: break;
1296: }
1297: }
1298: enumerator->destroy(enumerator);
1299: }
1300:
1301: if (status == SUCCESS && this->trap)
1302: {
1303: set_state(this, CHILD_ROUTED);
1304: }
1305: return status;
1306: }
1307:
1308: METHOD(child_sa_t, register_outbound, status_t,
1309: private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
1310: uint16_t cpi, bool tfcv3)
1311: {
1312: status_t status;
1313:
1314: /* if the kernel supports installing SPIs with policies we install the
1315: * SA immediately as it will only be used once we update the policies */
1316: if (charon->kernel->get_features(charon->kernel) & KERNEL_POLICY_SPI)
1317: {
1318: status = install_internal(this, encr, integ, spi, cpi, FALSE, FALSE,
1319: tfcv3);
1320: }
1321: else
1322: {
1323: DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names,
1324: this->protocol);
1325: DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr,
1326: this->other_addr);
1327:
1328: this->other_spi = spi;
1329: this->other_cpi = cpi;
1330: this->encr_r = chunk_clone(encr);
1331: this->integ_r = chunk_clone(integ);
1332: this->tfcv3 = tfcv3;
1333: status = SUCCESS;
1334: }
1335: this->outbound_state |= CHILD_OUTBOUND_REGISTERED;
1336: return status;
1337: }
1338:
1339: METHOD(child_sa_t, install_outbound, status_t,
1340: private_child_sa_t *this)
1341: {
1342: enumerator_t *enumerator;
1343: traffic_selector_t *my_ts, *other_ts;
1344: status_t status = SUCCESS;
1345:
1346: if (!(this->outbound_state & CHILD_OUTBOUND_SA))
1347: {
1348: status = install_internal(this, this->encr_r, this->integ_r,
1349: this->other_spi, this->other_cpi, FALSE,
1350: FALSE, this->tfcv3);
1351: chunk_clear(&this->encr_r);
1352: chunk_clear(&this->integ_r);
1353: }
1354: this->outbound_state &= ~CHILD_OUTBOUND_REGISTERED;
1355: if (status != SUCCESS)
1356: {
1357: return status;
1358: }
1359: if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
1360: !(this->outbound_state & CHILD_OUTBOUND_POLICIES))
1361: {
1362: ipsec_sa_cfg_t my_sa, other_sa;
1363: uint32_t manual_prio;
1364:
1365: prepare_sa_cfg(this, &my_sa, &other_sa);
1366: manual_prio = this->config->get_manual_prio(this->config);
1367:
1368: enumerator = create_policy_enumerator(this);
1369: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
1370: {
1371: status |= install_policies_outbound(this, this->my_addr,
1372: this->other_addr, my_ts, other_ts,
1373: &my_sa, &other_sa, POLICY_IPSEC,
1374: POLICY_PRIORITY_DEFAULT, manual_prio);
1375: if (status != SUCCESS)
1376: {
1377: break;
1378: }
1379: }
1380: enumerator->destroy(enumerator);
1381: }
1382: this->outbound_state |= CHILD_OUTBOUND_POLICIES;
1383: return status;
1384: }
1385:
1386: METHOD(child_sa_t, remove_outbound, void,
1387: private_child_sa_t *this)
1388: {
1389: enumerator_t *enumerator;
1390: traffic_selector_t *my_ts, *other_ts;
1391:
1392: if (!(this->outbound_state & CHILD_OUTBOUND_SA))
1393: {
1394: if (this->outbound_state & CHILD_OUTBOUND_REGISTERED)
1395: {
1396: chunk_clear(&this->encr_r);
1397: chunk_clear(&this->integ_r);
1398: this->outbound_state = CHILD_OUTBOUND_NONE;
1399: }
1400: return;
1401: }
1402:
1403: if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
1404: (this->outbound_state & CHILD_OUTBOUND_POLICIES))
1405: {
1406: ipsec_sa_cfg_t my_sa, other_sa;
1407: uint32_t manual_prio;
1408:
1409: prepare_sa_cfg(this, &my_sa, &other_sa);
1410: manual_prio = this->config->get_manual_prio(this->config);
1411:
1412: enumerator = create_policy_enumerator(this);
1413: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
1414: {
1415: del_policies_outbound(this, this->my_addr, this->other_addr,
1416: my_ts, other_ts, &my_sa, &other_sa,
1417: POLICY_IPSEC, POLICY_PRIORITY_DEFAULT,
1418: manual_prio);
1419: }
1420: enumerator->destroy(enumerator);
1421: }
1422:
1423: kernel_ipsec_sa_id_t id = {
1424: .src = this->my_addr,
1425: .dst = this->other_addr,
1426: .spi = this->other_spi,
1427: .proto = proto_ike2ip(this->protocol),
1428: .mark = this->mark_out,
1429: .if_id = this->if_id_out,
1430: };
1431: kernel_ipsec_del_sa_t sa = {
1432: .cpi = this->other_cpi,
1433: };
1434: charon->kernel->del_sa(charon->kernel, &id, &sa);
1435: this->outbound_state = CHILD_OUTBOUND_NONE;
1436: }
1437:
1438: METHOD(child_sa_t, set_rekey_spi, void,
1439: private_child_sa_t *this, uint32_t spi)
1440: {
1441: this->rekey_spi = spi;
1442: }
1443:
1444: METHOD(child_sa_t, get_rekey_spi, uint32_t,
1445: private_child_sa_t *this)
1446: {
1447: return this->rekey_spi;
1448: }
1449:
1450: CALLBACK(reinstall_vip, void,
1451: host_t *vip, va_list args)
1452: {
1453: host_t *me;
1454: char *iface;
1455:
1456: VA_ARGS_VGET(args, me);
1457: if (charon->kernel->get_interface(charon->kernel, me, &iface))
1458: {
1459: charon->kernel->del_ip(charon->kernel, vip, -1, TRUE);
1460: charon->kernel->add_ip(charon->kernel, vip, -1, iface);
1461: free(iface);
1462: }
1463: }
1464:
1465: /**
1466: * Update addresses and encap state of IPsec SAs in the kernel
1467: */
1468: static status_t update_sas(private_child_sa_t *this, host_t *me, host_t *other,
1469: bool encap)
1470: {
1471: /* update our (initiator) SA */
1472: if (this->my_spi)
1473: {
1474: kernel_ipsec_sa_id_t id = {
1475: .src = this->other_addr,
1476: .dst = this->my_addr,
1477: .spi = this->my_spi,
1478: .proto = proto_ike2ip(this->protocol),
1479: .mark = mark_in_sa(this),
1480: .if_id = this->if_id_in,
1481: };
1482: kernel_ipsec_update_sa_t sa = {
1483: .cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
1484: .new_src = other,
1485: .new_dst = me,
1486: .encap = this->encap,
1487: .new_encap = encap,
1488: };
1489: if (charon->kernel->update_sa(charon->kernel, &id,
1490: &sa) == NOT_SUPPORTED)
1491: {
1492: return NOT_SUPPORTED;
1493: }
1494: }
1495:
1496: /* update his (responder) SA */
1497: if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
1498: {
1499: kernel_ipsec_sa_id_t id = {
1500: .src = this->my_addr,
1501: .dst = this->other_addr,
1502: .spi = this->other_spi,
1503: .proto = proto_ike2ip(this->protocol),
1504: .mark = this->mark_out,
1505: .if_id = this->if_id_out,
1506: };
1507: kernel_ipsec_update_sa_t sa = {
1508: .cpi = this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
1509: .new_src = me,
1510: .new_dst = other,
1511: .encap = this->encap,
1512: .new_encap = encap,
1513: };
1514: if (charon->kernel->update_sa(charon->kernel, &id,
1515: &sa) == NOT_SUPPORTED)
1516: {
1517: return NOT_SUPPORTED;
1518: }
1519: }
1520: /* we currently ignore the actual return values above */
1521: return SUCCESS;
1522: }
1523:
1524: METHOD(child_sa_t, update, status_t,
1525: private_child_sa_t *this, host_t *me, host_t *other, linked_list_t *vips,
1526: bool encap)
1527: {
1528: child_sa_state_t old;
1529: bool transport_proxy_mode;
1530:
1531: /* anything changed at all? */
1532: if (me->equals(me, this->my_addr) &&
1533: other->equals(other, this->other_addr) && this->encap == encap)
1534: {
1535: return SUCCESS;
1536: }
1537:
1538: old = this->state;
1539: set_state(this, CHILD_UPDATING);
1540: transport_proxy_mode = this->mode == MODE_TRANSPORT &&
1541: this->config->has_option(this->config,
1542: OPT_PROXY_MODE);
1543:
1544: if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
1545: require_policy_update())
1546: {
1547: ipsec_sa_cfg_t my_sa, other_sa;
1548: enumerator_t *enumerator;
1549: traffic_selector_t *my_ts, *other_ts;
1550: uint32_t manual_prio;
1551: status_t state;
1552: bool outbound;
1553:
1554: prepare_sa_cfg(this, &my_sa, &other_sa);
1555: manual_prio = this->config->get_manual_prio(this->config);
1556: outbound = (this->outbound_state & CHILD_OUTBOUND_POLICIES);
1557:
1558: enumerator = create_policy_enumerator(this);
1559: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
1560: {
1561: /* install drop policy to avoid traffic leaks, acquires etc. */
1562: if (outbound)
1563: {
1564: install_policies_outbound(this, this->my_addr, this->other_addr,
1565: my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP,
1566: POLICY_PRIORITY_DEFAULT, manual_prio);
1567: }
1568: /* remove old policies */
1569: del_policies_internal(this, this->my_addr, this->other_addr,
1570: my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC,
1571: POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
1572: }
1573: enumerator->destroy(enumerator);
1574:
1575: /* update the IPsec SAs */
1576: state = update_sas(this, me, other, encap);
1577:
1578: enumerator = create_policy_enumerator(this);
1579: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
1580: {
1581: traffic_selector_t *old_my_ts = NULL, *old_other_ts = NULL;
1582:
1583: /* reinstall the previous policies if we can't update the SAs */
1584: if (state == NOT_SUPPORTED)
1585: {
1586: install_policies_internal(this, this->my_addr, this->other_addr,
1587: my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC,
1588: POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
1589: }
1590: else
1591: {
1592: /* check if we have to update a "dynamic" traffic selector */
1593: if (!me->ip_equals(me, this->my_addr) &&
1594: my_ts->is_host(my_ts, this->my_addr))
1595: {
1596: old_my_ts = my_ts->clone(my_ts);
1597: my_ts->set_address(my_ts, me);
1598: }
1599: if (!other->ip_equals(other, this->other_addr) &&
1600: other_ts->is_host(other_ts, this->other_addr))
1601: {
1602: old_other_ts = other_ts->clone(other_ts);
1603: other_ts->set_address(other_ts, other);
1604: }
1605:
1606: /* we reinstall the virtual IP to handle interface roaming
1607: * correctly */
1608: vips->invoke_function(vips, reinstall_vip, me);
1609:
1610: /* reinstall updated policies */
1611: install_policies_internal(this, me, other, my_ts, other_ts,
1612: &my_sa, &other_sa, POLICY_IPSEC,
1613: POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
1614: }
1615: /* remove the drop policy */
1616: if (outbound)
1617: {
1618: del_policies_outbound(this, this->my_addr, this->other_addr,
1619: old_my_ts ?: my_ts, old_other_ts ?: other_ts,
1620: &my_sa, &other_sa, POLICY_DROP,
1621: POLICY_PRIORITY_DEFAULT, manual_prio);
1622: }
1623:
1624: DESTROY_IF(old_my_ts);
1625: DESTROY_IF(old_other_ts);
1626: }
1627: enumerator->destroy(enumerator);
1628:
1629: if (state == NOT_SUPPORTED)
1630: {
1631: set_state(this, old);
1632: return NOT_SUPPORTED;
1633: }
1634:
1635: }
1636: else if (!transport_proxy_mode)
1637: {
1638: if (update_sas(this, me, other, encap) == NOT_SUPPORTED)
1639: {
1640: set_state(this, old);
1641: return NOT_SUPPORTED;
1642: }
1643: }
1644:
1645: if (!transport_proxy_mode)
1646: {
1647: /* apply hosts */
1648: if (!me->equals(me, this->my_addr))
1649: {
1650: this->my_addr->destroy(this->my_addr);
1651: this->my_addr = me->clone(me);
1652: }
1653: if (!other->equals(other, this->other_addr))
1654: {
1655: this->other_addr->destroy(this->other_addr);
1656: this->other_addr = other->clone(other);
1657: }
1658: }
1659:
1660: this->encap = encap;
1661: set_state(this, old);
1662:
1663: return SUCCESS;
1664: }
1665:
1666: METHOD(child_sa_t, destroy, void,
1667: private_child_sa_t *this)
1668: {
1669: enumerator_t *enumerator;
1670: traffic_selector_t *my_ts, *other_ts;
1671: policy_priority_t priority;
1672:
1673: priority = this->trap ? POLICY_PRIORITY_ROUTED : POLICY_PRIORITY_DEFAULT;
1674:
1675: set_state(this, CHILD_DESTROYING);
1676:
1677: if (!this->config->has_option(this->config, OPT_NO_POLICIES))
1678: {
1679: ipsec_sa_cfg_t my_sa, other_sa;
1680: uint32_t manual_prio;
1681: bool del_outbound;
1682:
1683: prepare_sa_cfg(this, &my_sa, &other_sa);
1684: manual_prio = this->config->get_manual_prio(this->config);
1685: del_outbound = (this->outbound_state & CHILD_OUTBOUND_POLICIES) ||
1686: this->trap;
1687:
1688: /* delete all policies in the kernel */
1689: enumerator = create_policy_enumerator(this);
1690: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
1691: {
1692: del_policies_internal(this, this->my_addr,
1693: this->other_addr, my_ts, other_ts, &my_sa, &other_sa,
1694: POLICY_IPSEC, priority, manual_prio, del_outbound);
1695: }
1696: enumerator->destroy(enumerator);
1697: }
1698:
1699: /* delete SAs in the kernel, if they are set up */
1700: if (this->my_spi)
1701: {
1702: kernel_ipsec_sa_id_t id = {
1703: .src = this->other_addr,
1704: .dst = this->my_addr,
1705: .spi = this->my_spi,
1706: .proto = proto_ike2ip(this->protocol),
1707: .mark = mark_in_sa(this),
1708: .if_id = this->if_id_in,
1709: };
1710: kernel_ipsec_del_sa_t sa = {
1711: .cpi = this->my_cpi,
1712: };
1713: charon->kernel->del_sa(charon->kernel, &id, &sa);
1714: }
1715: if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
1716: {
1717: kernel_ipsec_sa_id_t id = {
1718: .src = this->my_addr,
1719: .dst = this->other_addr,
1720: .spi = this->other_spi,
1721: .proto = proto_ike2ip(this->protocol),
1722: .mark = this->mark_out,
1723: .if_id = this->if_id_out,
1724: };
1725: kernel_ipsec_del_sa_t sa = {
1726: .cpi = this->other_cpi,
1727: };
1728: charon->kernel->del_sa(charon->kernel, &id, &sa);
1729: }
1730:
1731: if (this->reqid_allocated)
1732: {
1733: if (charon->kernel->release_reqid(charon->kernel,
1734: this->reqid, this->mark_in, this->mark_out,
1735: this->if_id_in, this->if_id_out) != SUCCESS)
1736: {
1737: DBG1(DBG_CHD, "releasing reqid %u failed", this->reqid);
1738: }
1739: }
1740:
1741: array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
1742: array_destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
1743: this->my_addr->destroy(this->my_addr);
1744: this->other_addr->destroy(this->other_addr);
1745: DESTROY_IF(this->proposal);
1746: this->config->destroy(this->config);
1747: chunk_clear(&this->encr_r);
1748: chunk_clear(&this->integ_r);
1749: free(this);
1750: }
1751:
1752: /**
1753: * Get proxy address for one side, if any
1754: */
1755: static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
1756: {
1757: host_t *host = NULL;
1758: uint8_t mask;
1759: enumerator_t *enumerator;
1760: linked_list_t *ts_list, *list;
1761: traffic_selector_t *ts;
1762:
1763: list = linked_list_create_with_items(ike, NULL);
1764: ts_list = config->get_traffic_selectors(config, local, NULL, list, FALSE);
1765: list->destroy(list);
1766:
1767: enumerator = ts_list->create_enumerator(ts_list);
1768: while (enumerator->enumerate(enumerator, &ts))
1769: {
1770: if (ts->is_host(ts, NULL) && ts->to_subnet(ts, &host, &mask))
1771: {
1772: DBG1(DBG_CHD, "%s address: %H is a transport mode proxy for %H",
1773: local ? "my" : "other", ike, host);
1774: break;
1775: }
1776: }
1777: enumerator->destroy(enumerator);
1778: ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
1779:
1780: if (!host)
1781: {
1782: host = ike->clone(ike);
1783: }
1784: return host;
1785: }
1786:
1787: /*
1788: * Described in header
1789: */
1790: child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
1791: child_sa_create_t *data)
1792: {
1793: private_child_sa_t *this;
1794: static refcount_t unique_id = 0, unique_mark = 0;
1795:
1796: INIT(this,
1797: .public = {
1798: .get_name = _get_name,
1799: .get_reqid = _get_reqid,
1800: .get_unique_id = _get_unique_id,
1801: .get_config = _get_config,
1802: .get_state = _get_state,
1803: .set_state = _set_state,
1804: .get_outbound_state = _get_outbound_state,
1805: .get_spi = _get_spi,
1806: .get_cpi = _get_cpi,
1807: .get_protocol = _get_protocol,
1808: .set_protocol = _set_protocol,
1809: .get_mode = _get_mode,
1810: .set_mode = _set_mode,
1811: .get_proposal = _get_proposal,
1812: .set_proposal = _set_proposal,
1813: .get_lifetime = _get_lifetime,
1814: .get_installtime = _get_installtime,
1815: .get_usestats = _get_usestats,
1816: .get_mark = _get_mark,
1817: .get_if_id = _get_if_id,
1818: .has_encap = _has_encap,
1819: .get_ipcomp = _get_ipcomp,
1820: .set_ipcomp = _set_ipcomp,
1821: .get_close_action = _get_close_action,
1822: .set_close_action = _set_close_action,
1823: .get_dpd_action = _get_dpd_action,
1824: .set_dpd_action = _set_dpd_action,
1825: .alloc_spi = _alloc_spi,
1826: .alloc_cpi = _alloc_cpi,
1827: .install = _install,
1828: .register_outbound = _register_outbound,
1829: .install_outbound = _install_outbound,
1830: .remove_outbound = _remove_outbound,
1831: .set_rekey_spi = _set_rekey_spi,
1832: .get_rekey_spi = _get_rekey_spi,
1833: .update = _update,
1834: .set_policies = _set_policies,
1835: .install_policies = _install_policies,
1836: .create_ts_enumerator = _create_ts_enumerator,
1837: .create_policy_enumerator = _create_policy_enumerator,
1838: .destroy = _destroy,
1839: },
1840: .encap = data->encap,
1841: .ipcomp = IPCOMP_NONE,
1842: .state = CHILD_CREATED,
1843: .my_ts = array_create(0, 0),
1844: .other_ts = array_create(0, 0),
1845: .protocol = PROTO_NONE,
1846: .mode = MODE_TUNNEL,
1847: .close_action = config->get_close_action(config),
1848: .dpd_action = config->get_dpd_action(config),
1849: .reqid = config->get_reqid(config),
1850: .unique_id = ref_get(&unique_id),
1851: .mark_in = config->get_mark(config, TRUE),
1852: .mark_out = config->get_mark(config, FALSE),
1853: .if_id_in = config->get_if_id(config, TRUE) ?: data->if_id_in_def,
1854: .if_id_out = config->get_if_id(config, FALSE) ?: data->if_id_out_def,
1855: .install_time = time_monotonic(NULL),
1856: .policies_fwd_out = config->has_option(config, OPT_FWD_OUT_POLICIES),
1857: );
1858:
1859: this->config = config;
1860: config->get_ref(config);
1861:
1862: if (data->mark_in)
1863: {
1864: this->mark_in.value = data->mark_in;
1865: }
1866: if (data->mark_out)
1867: {
1868: this->mark_out.value = data->mark_out;
1869: }
1870: if (data->if_id_in)
1871: {
1872: this->if_id_in = data->if_id_in;
1873: }
1874: if (data->if_id_out)
1875: {
1876: this->if_id_out = data->if_id_out;
1877: }
1878:
1879: allocate_unique_if_ids(&this->if_id_in, &this->if_id_out);
1880:
1881: if (MARK_IS_UNIQUE(this->mark_in.value) ||
1882: MARK_IS_UNIQUE(this->mark_out.value))
1883: {
1884: refcount_t mark = 0;
1885: bool unique_dir = this->mark_in.value == MARK_UNIQUE_DIR ||
1886: this->mark_out.value == MARK_UNIQUE_DIR;
1887:
1888: if (!unique_dir)
1889: {
1890: mark = ref_get(&unique_mark);
1891: }
1892: if (MARK_IS_UNIQUE(this->mark_in.value))
1893: {
1894: this->mark_in.value = unique_dir ? ref_get(&unique_mark) : mark;
1895: }
1896: if (MARK_IS_UNIQUE(this->mark_out.value))
1897: {
1898: this->mark_out.value = unique_dir ? ref_get(&unique_mark) : mark;
1899: }
1900: }
1901:
1902: if (!this->reqid)
1903: {
1904: /* reuse old reqid if we are rekeying an existing CHILD_SA and when
1905: * initiating a trap policy. While the reqid cache would find the same
1906: * reqid for our selectors, this does not work in a special case: If an
1907: * SA is triggered by a trap policy, but the negotiated TS get
1908: * narrowed, we still must reuse the same reqid to successfully
1909: * replace the temporary SA on the kernel level. Rekeying such an SA
1910: * requires an explicit reqid, as the cache currently knows the original
1911: * selectors only for that reqid. */
1912: this->reqid = data->reqid;
1913: }
1914: else
1915: {
1916: this->static_reqid = TRUE;
1917: }
1918:
1919: /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
1920: if (config->get_mode(config) == MODE_TRANSPORT &&
1921: config->has_option(config, OPT_PROXY_MODE))
1922: {
1923: this->mode = MODE_TRANSPORT;
1924:
1925: this->my_addr = get_proxy_addr(config, me, TRUE);
1926: this->other_addr = get_proxy_addr(config, other, FALSE);
1927: }
1928: else
1929: {
1930: this->my_addr = me->clone(me);
1931: this->other_addr = other->clone(other);
1932: }
1933: return &this->public;
1934: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>