using same reqid if a child sa rekeys an existing one
[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 * Protocol used to protect this SA, ESP|AH
72 */
73 protocol_id_t protocol;
74
75 /**
76 * List containing sa_policy_t objects
77 */
78 linked_list_t *policies;
79
80 /**
81 * reqid used for this child_sa
82 */
83 u_int32_t reqid;
84
85 /**
86 * time, on which SA was installed
87 */
88 time_t install_time;
89
90 /**
91 * Lifetime before rekeying
92 */
93 u_int32_t soft_lifetime;
94
95 /**
96 * Lifetime before delete
97 */
98 u_int32_t hard_lifetime;
99
100 /**
101 * reqid of a CHILD_SA which rekeyed this one
102 */
103 u_int32_t rekeyed;
104
105 /**
106 * CHILD_SAs own logger
107 */
108 logger_t *logger;
109 };
110
111 /**
112 * Implements child_sa_t.get_reqid
113 */
114 static u_int32_t get_reqid(private_child_sa_t *this)
115 {
116 return this->reqid;
117 }
118
119 /**
120 * Implements child_sa_t.get_spi
121 */
122 u_int32_t get_spi(private_child_sa_t *this, bool inbound)
123 {
124 if (inbound)
125 {
126 return this->me.spi;
127 }
128 return this->other.spi;
129 }
130
131 /**
132 * Implements child_sa_t.get_protocol
133 */
134 protocol_id_t get_protocol(private_child_sa_t *this)
135 {
136 return this->protocol;
137 }
138
139 /**
140 * Implements child_sa_t.alloc
141 */
142 static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
143 {
144 protocol_id_t protocol;
145 iterator_t *iterator;
146 proposal_t *proposal;
147 status_t status;
148
149 /* iterator through proposals */
150 iterator = proposals->create_iterator(proposals, TRUE);
151 while(iterator->has_next(iterator))
152 {
153 iterator->current(iterator, (void**)&proposal);
154 protocol = proposal->get_protocol(proposal);
155
156 status = charon->kernel_interface->get_spi(
157 charon->kernel_interface,
158 this->other.addr, this->me.addr,
159 protocol, this->reqid,
160 &this->me.spi);
161
162 if (status != SUCCESS)
163 {
164 iterator->destroy(iterator);
165 return FAILED;
166 }
167 /* update proposal */
168 proposal->set_spi(proposal, (u_int64_t)this->me.spi);
169 }
170 iterator->destroy(iterator);
171 return SUCCESS;
172 }
173
174 static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine)
175 {
176 u_int32_t spi;
177 algorithm_t *enc_algo, *int_algo;
178 algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0};
179 algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
180 host_t *src;
181 host_t *dst;
182 status_t status;
183
184 /* we must assign the roles to correctly set up the SAs */
185 if (mine)
186 {
187 dst = this->me.addr;
188 src = this->other.addr;
189 }
190 else
191 {
192 src = this->me.addr;
193 dst = this->other.addr;
194 }
195
196 this->protocol = proposal->get_protocol(proposal);
197
198 /* now we have to decide which spi to use. Use self allocated, if "mine",
199 * or the one in the proposal, if not "mine" (others). */
200 if (mine)
201 {
202 spi = this->me.spi;
203 }
204 else
205 {
206 spi = proposal->get_spi(proposal);
207 this->other.spi = spi;
208 }
209
210 this->logger->log(this->logger, CONTROL|LEVEL1, "Adding %s %s SA",
211 mine ? "inbound" : "outbound",
212 mapping_find(protocol_id_m, this->protocol));
213
214 /* select encryption algo */
215 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_algo))
216 {
217 this->logger->log(this->logger, CONTROL|LEVEL2, " using %s for encryption",
218 mapping_find(encryption_algorithm_m, enc_algo->algorithm));
219 }
220 else
221 {
222 enc_algo = &enc_algo_none;
223 }
224
225 /* select integrity algo */
226 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_algo))
227 {
228 this->logger->log(this->logger, CONTROL|LEVEL2, " using %s for integrity",
229 mapping_find(integrity_algorithm_m, int_algo->algorithm));
230 }
231 else
232 {
233 int_algo = &int_algo_none;
234 }
235
236 /* send SA down to the kernel */
237 this->logger->log(this->logger, CONTROL|LEVEL2,
238 " SPI 0x%.8x, src %s dst %s",
239 ntohl(spi), src->get_address(src), dst->get_address(dst));
240 status = charon->kernel_interface->add_sa(charon->kernel_interface,
241 src, dst,
242 spi, this->protocol,
243 this->reqid,
244 mine ? 0 : this->soft_lifetime,
245 this->hard_lifetime,
246 enc_algo, int_algo, prf_plus, mine);
247
248 this->install_time = time(NULL);
249
250 return status;
251 }
252
253 static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
254 {
255 linked_list_t *list;
256
257 /* install others (initiators) SAs*/
258 if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
259 {
260 return FAILED;
261 }
262
263 /* get SPIs for our SAs */
264 list = linked_list_create();
265 list->insert_last(list, proposal);
266 if (alloc(this, list) != SUCCESS)
267 {
268 list->destroy(list);
269 return FAILED;
270 }
271 list->destroy(list);
272
273 /* install our (responders) SAs */
274 if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
275 {
276 return FAILED;
277 }
278
279 return SUCCESS;
280 }
281
282 static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
283 {
284 /* install our (initator) SAs */
285 if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
286 {
287 return FAILED;
288 }
289 /* install his (responder) SAs */
290 if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
291 {
292 return FAILED;
293 }
294
295 return SUCCESS;
296 }
297
298 static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list)
299 {
300 iterator_t *my_iter, *other_iter;
301 traffic_selector_t *my_ts, *other_ts;
302
303 /* iterate over both lists */
304 my_iter = my_ts_list->create_iterator(my_ts_list, TRUE);
305 other_iter = other_ts_list->create_iterator(other_ts_list, TRUE);
306 while (my_iter->has_next(my_iter))
307 {
308 my_iter->current(my_iter, (void**)&my_ts);
309 other_iter->reset(other_iter);
310 while (other_iter->has_next(other_iter))
311 {
312 /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
313 int family;
314 chunk_t from_addr;
315 u_int16_t from_port, to_port;
316 sa_policy_t *policy;
317 status_t status;
318
319 other_iter->current(other_iter, (void**)&other_ts);
320
321 /* only set up policies if protocol matches */
322 if (my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts))
323 {
324 continue;
325 }
326 policy = malloc_thing(sa_policy_t);
327 policy->upper_proto = my_ts->get_protocol(my_ts);
328
329 /* calculate net and ports for local side */
330 family = my_ts->get_type(my_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
331 from_addr = my_ts->get_from_address(my_ts);
332 from_port = my_ts->get_from_port(my_ts);
333 to_port = my_ts->get_to_port(my_ts);
334 from_port = (from_port != to_port) ? 0 : from_port;
335 policy->me.net = host_create_from_chunk(family, from_addr, from_port);
336 policy->me.net_mask = my_ts->get_netmask(my_ts);
337 chunk_free(&from_addr);
338
339 /* calculate net and ports for remote side */
340 family = other_ts->get_type(other_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
341 from_addr = other_ts->get_from_address(other_ts);
342 from_port = other_ts->get_from_port(other_ts);
343 to_port = other_ts->get_to_port(other_ts);
344 from_port = (from_port != to_port) ? 0 : from_port;
345 policy->other.net = host_create_from_chunk(family, from_addr, from_port);
346 policy->other.net_mask = other_ts->get_netmask(other_ts);
347 chunk_free(&from_addr);
348
349 /* install 3 policies: out, in and forward */
350 status = charon->kernel_interface->add_policy(charon->kernel_interface,
351 this->me.addr, this->other.addr,
352 policy->me.net, policy->other.net,
353 policy->me.net_mask, policy->other.net_mask,
354 XFRM_POLICY_OUT, policy->upper_proto,
355 this->protocol,
356 this->reqid);
357
358 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
359 this->other.addr, this->me.addr,
360 policy->other.net, policy->me.net,
361 policy->other.net_mask, policy->me.net_mask,
362 XFRM_POLICY_IN, policy->upper_proto,
363 this->protocol,
364 this->reqid);
365
366 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
367 this->other.addr, this->me.addr,
368 policy->other.net, policy->me.net,
369 policy->other.net_mask, policy->me.net_mask,
370 XFRM_POLICY_FWD, policy->upper_proto,
371 this->protocol,
372 this->reqid);
373
374 if (status != SUCCESS)
375 {
376 my_iter->destroy(my_iter);
377 other_iter->destroy(other_iter);
378 policy->me.net->destroy(policy->me.net);
379 policy->other.net->destroy(policy->other.net);
380 free(policy);
381 return status;
382 }
383
384 /* add it to the policy list, since we want to know which policies we own */
385 this->policies->insert_last(this->policies, policy);
386 }
387 }
388 my_iter->destroy(my_iter);
389 other_iter->destroy(other_iter);
390 return SUCCESS;
391 }
392
393 /**
394 * Implementation of child_sa_t.set_rekeyed.
395 */
396 static void set_rekeyed(private_child_sa_t *this, u_int32_t reqid)
397 {
398 this->rekeyed = reqid;
399 }
400
401 /**
402 * Implementation of child_sa_t.log_status.
403 */
404 static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
405 {
406 iterator_t *iterator;
407 sa_policy_t *policy;
408 struct protoent *proto;
409 char proto_buf[8] = "";
410 char *proto_name = proto_buf;
411
412 if (logger == NULL)
413 {
414 logger = this->logger;
415 }
416 logger->log(logger, CONTROL|LEVEL1, " \"%s\": protected with %s (0x%x/0x%x), reqid %d, rekeying in %ds:",
417 name,
418 this->protocol == PROTO_ESP ? "ESP" : "AH",
419 htonl(this->me.spi), htonl(this->other.spi),
420 this->reqid,
421 this->soft_lifetime - (time(NULL) - this->install_time));
422 iterator = this->policies->create_iterator(this->policies, TRUE);
423 while (iterator->has_next(iterator))
424 {
425 iterator->current(iterator, (void**)&policy);
426 if (policy->upper_proto)
427 {
428 proto = getprotobynumber(policy->upper_proto);
429 if (proto)
430 {
431 proto_name = proto->p_name;
432 }
433 else
434 {
435 snprintf(proto_buf, sizeof(proto_buf), "<%d>", policy->upper_proto);
436 }
437 }
438 logger->log(logger, CONTROL, " \"%s\": %s/%d==%s==%s/%d",
439 name,
440 policy->me.net->get_address(policy->me.net), policy->me.net_mask,
441 proto_name,
442 policy->other.net->get_address(policy->other.net), policy->other.net_mask);
443 }
444 iterator->destroy(iterator);
445 }
446
447 /**
448 * Implementation of child_sa_t.destroy.
449 */
450 static void destroy(private_child_sa_t *this)
451 {
452 sa_policy_t *policy;
453
454 /* delete SAs in the kernel, if they are set up */
455 if (this->protocol != PROTO_NONE)
456 {
457 charon->kernel_interface->del_sa(charon->kernel_interface,
458 this->me.addr, this->me.spi, this->protocol);
459 charon->kernel_interface->del_sa(charon->kernel_interface,
460 this->other.addr, this->other.spi, this->protocol);
461 }
462
463 /* delete all policies in the kernel */
464 while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
465 {
466 if (!this->rekeyed)
467 {
468 /* let rekeyed policies, as they are used by another child_sa */
469 charon->kernel_interface->del_policy(charon->kernel_interface,
470 this->me.addr, this->other.addr,
471 policy->me.net, policy->other.net,
472 policy->me.net_mask, policy->other.net_mask,
473 XFRM_POLICY_OUT, policy->upper_proto);
474
475 charon->kernel_interface->del_policy(charon->kernel_interface,
476 this->other.addr, this->me.addr,
477 policy->other.net, policy->me.net,
478 policy->other.net_mask, policy->me.net_mask,
479 XFRM_POLICY_IN, policy->upper_proto);
480
481 charon->kernel_interface->del_policy(charon->kernel_interface,
482 this->other.addr, this->me.addr,
483 policy->other.net, policy->me.net,
484 policy->other.net_mask, policy->me.net_mask,
485 XFRM_POLICY_FWD, policy->upper_proto);
486 }
487 policy->me.net->destroy(policy->me.net);
488 policy->other.net->destroy(policy->other.net);
489 free(policy);
490 }
491 this->policies->destroy(this->policies);
492
493 free(this);
494 }
495
496 /*
497 * Described in header.
498 */
499 child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
500 u_int32_t soft_lifetime, u_int32_t hard_lifetime)
501 {
502 static u_int32_t reqid = 2000000000;
503 private_child_sa_t *this = malloc_thing(private_child_sa_t);
504
505 /* public functions */
506 this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
507 this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
508 this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
509 this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
510 this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
511 this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
512 this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
513 this->public.set_rekeyed = (void (*)(child_sa_t*,u_int32_t))set_rekeyed;
514 this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status;
515 this->public.destroy = (void(*)(child_sa_t*))destroy;
516
517 /* private data */
518 this->logger = logger_manager->get_logger(logger_manager, CHILD_SA);
519 this->me.addr = me;
520 this->other.addr = other;
521 this->me.spi = 0;
522 this->other.spi = 0;
523 this->soft_lifetime = soft_lifetime;
524 this->hard_lifetime = hard_lifetime;
525 /* reuse old reqid if we are rekeying an existing CHILD_SA */
526 this->reqid = rekey ? rekey : ++reqid;
527 this->policies = linked_list_create();
528 this->protocol = PROTO_NONE;
529 this->rekeyed = 0;
530
531 return (&this->public);
532 }