implemented clean spi allocation behavior when using multiple proposals
[strongswan.git] / src / charon / sa / child_sa.c
1 /**
2 * @file child_sa.c
3 *
4 * @brief Implementation of child_sa_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <netdb.h>
24
25 #include "child_sa.h"
26
27 #include <daemon.h>
28
29
30 typedef struct sa_policy_t sa_policy_t;
31
32 /**
33 * Struct used to store information for a policy. This
34 * is needed since we must provide all this information
35 * for deleting a policy...
36 */
37 struct sa_policy_t {
38
39 struct {
40 /** subnet address behind peer peer */
41 host_t *net;
42 /** netmask used for net */
43 u_int8_t net_mask;
44 } me, other;
45
46 /**
47 * Protocol for this policy, such as TCP/UDP/ICMP...
48 */
49 int upper_proto;
50 };
51
52 typedef struct private_child_sa_t private_child_sa_t;
53
54 /**
55 * Private data of a child_sa_t object.
56 */
57 struct private_child_sa_t {
58 /**
59 * Public interface of child_sa_t.
60 */
61 child_sa_t public;
62
63 struct {
64 /** address of peer */
65 host_t *addr;
66 /** actual used SPI, 0 if unused */
67 u_int32_t spi;
68 } me, other;
69
70 /**
71 * Allocated SPI for a ESP proposal candidates
72 */
73 u_int32_t alloc_esp_spi;
74
75 /**
76 * Allocated SPI for a AH proposal candidates
77 */
78 u_int32_t alloc_ah_spi;
79
80 /**
81 * Protocol used to protect this SA, ESP|AH
82 */
83 protocol_id_t protocol;
84
85 /**
86 * List containing sa_policy_t objects
87 */
88 linked_list_t *policies;
89
90 /**
91 * reqid used for this child_sa
92 */
93 u_int32_t reqid;
94
95 /**
96 * time, on which SA was installed
97 */
98 time_t install_time;
99
100 /**
101 * Lifetime before rekeying
102 */
103 u_int32_t soft_lifetime;
104
105 /**
106 * Lifetime before delete
107 */
108 u_int32_t hard_lifetime;
109
110 /**
111 * reqid of a CHILD_SA which rekeyed this one
112 */
113 u_int32_t rekeyed;
114
115 /**
116 * CHILD_SAs own logger
117 */
118 logger_t *logger;
119 };
120
121 /**
122 * Implements child_sa_t.get_reqid
123 */
124 static u_int32_t get_reqid(private_child_sa_t *this)
125 {
126 return this->reqid;
127 }
128
129 /**
130 * Implements child_sa_t.get_spi
131 */
132 u_int32_t get_spi(private_child_sa_t *this, bool inbound)
133 {
134 if (inbound)
135 {
136 return this->me.spi;
137 }
138 return this->other.spi;
139 }
140
141 /**
142 * Implements child_sa_t.get_protocol
143 */
144 protocol_id_t get_protocol(private_child_sa_t *this)
145 {
146 return this->protocol;
147 }
148
149 /**
150 * Implements child_sa_t.alloc
151 */
152 static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
153 {
154 protocol_id_t protocol;
155 iterator_t *iterator;
156 proposal_t *proposal;
157
158 /* iterator through proposals to update spis */
159 iterator = proposals->create_iterator(proposals, TRUE);
160 while(iterator->has_next(iterator))
161 {
162 iterator->current(iterator, (void**)&proposal);
163 protocol = proposal->get_protocol(proposal);
164
165 if (protocol == PROTO_AH)
166 {
167 /* get a new spi for AH, if not already done */
168 if (this->alloc_ah_spi == 0)
169 {
170 if (charon->kernel_interface->get_spi(
171 charon->kernel_interface,
172 this->other.addr, this->me.addr,
173 PROTO_AH, this->reqid,
174 &this->alloc_ah_spi) != SUCCESS)
175 {
176 return FAILED;
177 }
178 }
179 proposal->set_spi(proposal, this->alloc_ah_spi);
180 }
181 if (protocol == PROTO_ESP)
182 {
183 /* get a new spi for ESP, if not already done */
184 if (this->alloc_esp_spi == 0)
185 {
186 if (charon->kernel_interface->get_spi(
187 charon->kernel_interface,
188 this->other.addr, this->me.addr,
189 PROTO_ESP, this->reqid,
190 &this->alloc_esp_spi) != SUCCESS)
191 {
192 return FAILED;
193 }
194 }
195 proposal->set_spi(proposal, this->alloc_esp_spi);
196 }
197
198 }
199 iterator->destroy(iterator);
200 return SUCCESS;
201 }
202
203 static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine)
204 {
205 u_int32_t spi;
206 algorithm_t *enc_algo, *int_algo;
207 algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0};
208 algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
209 host_t *src;
210 host_t *dst;
211 status_t status;
212
213 this->protocol = proposal->get_protocol(proposal);
214
215 /* now we have to decide which spi to use. Use self allocated, if "mine",
216 * or the one in the proposal, if not "mine" (others). Additionally,
217 * source and dest host switch depending on the role */
218 if (mine)
219 {
220 /* if we have allocated SPIs for AH and ESP, we must delete the unused
221 * one. */
222 if (this->protocol == PROTO_ESP)
223 {
224 this->me.spi = this->alloc_esp_spi;
225 if (this->alloc_ah_spi)
226 {
227 charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr,
228 this->alloc_ah_spi, PROTO_AH);
229 }
230 }
231 else
232 {
233 this->me.spi = this->alloc_ah_spi;
234 if (this->alloc_esp_spi)
235 {
236 charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr,
237 this->alloc_esp_spi, PROTO_ESP);
238 }
239 }
240 spi = this->me.spi;
241 dst = this->me.addr;
242 src = this->other.addr;
243 }
244 else
245 {
246 this->other.spi = proposal->get_spi(proposal);
247 spi = this->other.spi;
248 src = this->me.addr;
249 dst = this->other.addr;
250 }
251
252 this->logger->log(this->logger, CONTROL|LEVEL1, "Adding %s %s SA",
253 mine ? "inbound" : "outbound",
254 mapping_find(protocol_id_m, this->protocol));
255
256 /* select encryption algo */
257 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_algo))
258 {
259 this->logger->log(this->logger, CONTROL|LEVEL2, " using %s for encryption",
260 mapping_find(encryption_algorithm_m, enc_algo->algorithm));
261 }
262 else
263 {
264 enc_algo = &enc_algo_none;
265 }
266
267 /* select integrity algo */
268 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_algo))
269 {
270 this->logger->log(this->logger, CONTROL|LEVEL2, " using %s for integrity",
271 mapping_find(integrity_algorithm_m, int_algo->algorithm));
272 }
273 else
274 {
275 int_algo = &int_algo_none;
276 }
277
278 /* send SA down to the kernel */
279 this->logger->log(this->logger, CONTROL|LEVEL2,
280 " SPI 0x%.8x, src %s dst %s",
281 ntohl(spi), src->get_address(src), dst->get_address(dst));
282 status = charon->kernel_interface->add_sa(charon->kernel_interface,
283 src, dst,
284 spi, this->protocol,
285 this->reqid,
286 mine ? 0 : this->soft_lifetime,
287 this->hard_lifetime,
288 enc_algo, int_algo, prf_plus, mine);
289
290 this->install_time = time(NULL);
291
292 return status;
293 }
294
295 static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
296 {
297 linked_list_t *list;
298
299 /* install others (initiators) SAs*/
300 if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
301 {
302 return FAILED;
303 }
304
305 /* get SPIs for our SAs */
306 list = linked_list_create();
307 list->insert_last(list, proposal);
308 if (alloc(this, list) != SUCCESS)
309 {
310 list->destroy(list);
311 return FAILED;
312 }
313 list->destroy(list);
314
315 /* install our (responders) SAs */
316 if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
317 {
318 return FAILED;
319 }
320
321 return SUCCESS;
322 }
323
324 static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
325 {
326 /* install our (initator) SAs */
327 if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
328 {
329 return FAILED;
330 }
331 /* install his (responder) SAs */
332 if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
333 {
334 return FAILED;
335 }
336
337 return SUCCESS;
338 }
339
340 static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list)
341 {
342 iterator_t *my_iter, *other_iter;
343 traffic_selector_t *my_ts, *other_ts;
344
345 /* iterate over both lists */
346 my_iter = my_ts_list->create_iterator(my_ts_list, TRUE);
347 other_iter = other_ts_list->create_iterator(other_ts_list, TRUE);
348 while (my_iter->has_next(my_iter))
349 {
350 my_iter->current(my_iter, (void**)&my_ts);
351 other_iter->reset(other_iter);
352 while (other_iter->has_next(other_iter))
353 {
354 /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
355 int family;
356 chunk_t from_addr;
357 u_int16_t from_port, to_port;
358 sa_policy_t *policy;
359 status_t status;
360
361 other_iter->current(other_iter, (void**)&other_ts);
362
363 /* only set up policies if protocol matches */
364 if (my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts))
365 {
366 continue;
367 }
368 policy = malloc_thing(sa_policy_t);
369 policy->upper_proto = my_ts->get_protocol(my_ts);
370
371 /* calculate net and ports for local side */
372 family = my_ts->get_type(my_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
373 from_addr = my_ts->get_from_address(my_ts);
374 from_port = my_ts->get_from_port(my_ts);
375 to_port = my_ts->get_to_port(my_ts);
376 from_port = (from_port != to_port) ? 0 : from_port;
377 policy->me.net = host_create_from_chunk(family, from_addr, from_port);
378 policy->me.net_mask = my_ts->get_netmask(my_ts);
379 chunk_free(&from_addr);
380
381 /* calculate net and ports for remote side */
382 family = other_ts->get_type(other_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
383 from_addr = other_ts->get_from_address(other_ts);
384 from_port = other_ts->get_from_port(other_ts);
385 to_port = other_ts->get_to_port(other_ts);
386 from_port = (from_port != to_port) ? 0 : from_port;
387 policy->other.net = host_create_from_chunk(family, from_addr, from_port);
388 policy->other.net_mask = other_ts->get_netmask(other_ts);
389 chunk_free(&from_addr);
390
391 /* install 3 policies: out, in and forward */
392 status = charon->kernel_interface->add_policy(charon->kernel_interface,
393 this->me.addr, this->other.addr,
394 policy->me.net, policy->other.net,
395 policy->me.net_mask, policy->other.net_mask,
396 XFRM_POLICY_OUT, policy->upper_proto,
397 this->protocol,
398 this->reqid);
399
400 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
401 this->other.addr, this->me.addr,
402 policy->other.net, policy->me.net,
403 policy->other.net_mask, policy->me.net_mask,
404 XFRM_POLICY_IN, policy->upper_proto,
405 this->protocol,
406 this->reqid);
407
408 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
409 this->other.addr, this->me.addr,
410 policy->other.net, policy->me.net,
411 policy->other.net_mask, policy->me.net_mask,
412 XFRM_POLICY_FWD, policy->upper_proto,
413 this->protocol,
414 this->reqid);
415
416 if (status != SUCCESS)
417 {
418 my_iter->destroy(my_iter);
419 other_iter->destroy(other_iter);
420 policy->me.net->destroy(policy->me.net);
421 policy->other.net->destroy(policy->other.net);
422 free(policy);
423 return status;
424 }
425
426 /* add it to the policy list, since we want to know which policies we own */
427 this->policies->insert_last(this->policies, policy);
428 }
429 }
430 my_iter->destroy(my_iter);
431 other_iter->destroy(other_iter);
432 return SUCCESS;
433 }
434
435 /**
436 * Implementation of child_sa_t.set_rekeyed.
437 */
438 static void set_rekeyed(private_child_sa_t *this, u_int32_t reqid)
439 {
440 this->rekeyed = reqid;
441 }
442
443 /**
444 * Implementation of child_sa_t.log_status.
445 */
446 static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
447 {
448 iterator_t *iterator;
449 sa_policy_t *policy;
450 struct protoent *proto;
451 char proto_buf[8] = "";
452 char *proto_name = proto_buf;
453
454 if (logger == NULL)
455 {
456 logger = this->logger;
457 }
458 if (this->soft_lifetime)
459 {
460 logger->log(logger, CONTROL|LEVEL1, " \"%s\": protected with %s (0x%x/0x%x), reqid %d, rekeying in %ds:",
461 name,
462 this->protocol == PROTO_ESP ? "ESP" : "AH",
463 htonl(this->me.spi), htonl(this->other.spi),
464 this->reqid,
465 this->soft_lifetime - (time(NULL) - this->install_time));
466 }
467 else
468 {
469
470 logger->log(logger, CONTROL|LEVEL1, " \"%s\": protected with %s (0x%x/0x%x), reqid %d, no rekeying:",
471 name,
472 this->protocol == PROTO_ESP ? "ESP" : "AH",
473 htonl(this->me.spi), htonl(this->other.spi),
474 this->reqid);
475 }
476 iterator = this->policies->create_iterator(this->policies, TRUE);
477 while (iterator->has_next(iterator))
478 {
479 iterator->current(iterator, (void**)&policy);
480 if (policy->upper_proto)
481 {
482 proto = getprotobynumber(policy->upper_proto);
483 if (proto)
484 {
485 proto_name = proto->p_name;
486 }
487 else
488 {
489 snprintf(proto_buf, sizeof(proto_buf), "<%d>", policy->upper_proto);
490 }
491 }
492 logger->log(logger, CONTROL, " \"%s\": %s/%d==%s==%s/%d",
493 name,
494 policy->me.net->get_address(policy->me.net), policy->me.net_mask,
495 proto_name,
496 policy->other.net->get_address(policy->other.net), policy->other.net_mask);
497 }
498 iterator->destroy(iterator);
499 }
500
501 /**
502 * Implementation of child_sa_t.destroy.
503 */
504 static void destroy(private_child_sa_t *this)
505 {
506 sa_policy_t *policy;
507
508 /* delete SAs in the kernel, if they are set up */
509 if (this->me.spi)
510 {
511 charon->kernel_interface->del_sa(charon->kernel_interface,
512 this->me.addr, this->me.spi, this->protocol);
513 }
514 if (this->alloc_esp_spi && this->alloc_esp_spi != this->me.spi)
515 {
516 charon->kernel_interface->del_sa(charon->kernel_interface,
517 this->me.addr, this->alloc_esp_spi, PROTO_ESP);
518 }
519 if (this->alloc_ah_spi && this->alloc_ah_spi != this->me.spi)
520 {
521 charon->kernel_interface->del_sa(charon->kernel_interface,
522 this->me.addr, this->alloc_ah_spi, PROTO_AH);
523 }
524 if (this->other.spi)
525 {
526 charon->kernel_interface->del_sa(charon->kernel_interface,
527 this->other.addr, this->other.spi, this->protocol);
528 }
529
530 /* delete all policies in the kernel */
531 while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
532 {
533 if (!this->rekeyed)
534 {
535 /* let rekeyed policies, as they are used by another child_sa */
536 charon->kernel_interface->del_policy(charon->kernel_interface,
537 this->me.addr, this->other.addr,
538 policy->me.net, policy->other.net,
539 policy->me.net_mask, policy->other.net_mask,
540 XFRM_POLICY_OUT, policy->upper_proto);
541
542 charon->kernel_interface->del_policy(charon->kernel_interface,
543 this->other.addr, this->me.addr,
544 policy->other.net, policy->me.net,
545 policy->other.net_mask, policy->me.net_mask,
546 XFRM_POLICY_IN, policy->upper_proto);
547
548 charon->kernel_interface->del_policy(charon->kernel_interface,
549 this->other.addr, this->me.addr,
550 policy->other.net, policy->me.net,
551 policy->other.net_mask, policy->me.net_mask,
552 XFRM_POLICY_FWD, policy->upper_proto);
553 }
554 policy->me.net->destroy(policy->me.net);
555 policy->other.net->destroy(policy->other.net);
556 free(policy);
557 }
558 this->policies->destroy(this->policies);
559
560 free(this);
561 }
562
563 /*
564 * Described in header.
565 */
566 child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
567 u_int32_t soft_lifetime, u_int32_t hard_lifetime)
568 {
569 static u_int32_t reqid = 2000000000;
570 private_child_sa_t *this = malloc_thing(private_child_sa_t);
571
572 /* public functions */
573 this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
574 this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
575 this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
576 this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
577 this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
578 this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
579 this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
580 this->public.set_rekeyed = (void (*)(child_sa_t*,u_int32_t))set_rekeyed;
581 this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status;
582 this->public.destroy = (void(*)(child_sa_t*))destroy;
583
584 /* private data */
585 this->logger = logger_manager->get_logger(logger_manager, CHILD_SA);
586 this->me.addr = me;
587 this->other.addr = other;
588 this->me.spi = 0;
589 this->other.spi = 0;
590 this->alloc_ah_spi = 0;
591 this->alloc_esp_spi = 0;
592 this->soft_lifetime = soft_lifetime;
593 this->hard_lifetime = hard_lifetime;
594 /* reuse old reqid if we are rekeying an existing CHILD_SA */
595 this->reqid = rekey ? rekey : ++reqid;
596 this->policies = linked_list_create();
597 this->protocol = PROTO_NONE;
598 this->rekeyed = 0;
599
600 return (&this->public);
601 }