4 * @brief Implementation of child_sa_t.
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
30 typedef struct sa_policy_t sa_policy_t
;
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...
40 /** subnet address behind peer peer */
42 /** netmask used for net */
47 * Protocol for this policy, such as TCP/UDP/ICMP...
52 typedef struct private_child_sa_t private_child_sa_t
;
55 * Private data of a child_sa_t object.
57 struct private_child_sa_t
{
59 * Public interface of child_sa_t.
64 /** address of peer */
66 /** actual used SPI, 0 if unused */
71 * Protocol used to protect this SA, ESP|AH
73 protocol_id_t protocol
;
76 * List containing sa_policy_t objects
78 linked_list_t
*policies
;
81 * reqid used for this child_sa
86 * Lifetime before rekeying
88 u_int32_t soft_lifetime
;
91 * Lifetime before delete
93 u_int32_t hard_lifetime
;
96 * CHILD_SAs own logger
102 * Implements child_sa_t.get_reqid
104 static u_int32_t
get_reqid(private_child_sa_t
*this)
110 * Implements child_sa_t.get_spi
112 u_int32_t
get_spi(private_child_sa_t
*this, bool inbound
)
118 return this->other
.spi
;
122 * Implements child_sa_t.get_protocol
124 protocol_id_t
get_protocol(private_child_sa_t
*this)
126 return this->protocol
;
130 * Implements child_sa_t.alloc
132 static status_t
alloc(private_child_sa_t
*this, linked_list_t
*proposals
)
134 protocol_id_t protocol
;
135 iterator_t
*iterator
;
136 proposal_t
*proposal
;
140 /* iterator through proposals */
141 iterator
= proposals
->create_iterator(proposals
, TRUE
);
142 while(iterator
->has_next(iterator
))
144 iterator
->current(iterator
, (void**)&proposal
);
145 protocol
= proposal
->get_protocol(proposal
);
147 status
= charon
->kernel_interface
->get_spi(
148 charon
->kernel_interface
,
149 this->me
.addr
, this->other
.addr
,
153 if (status
!= SUCCESS
)
155 iterator
->destroy(iterator
);
158 /* update proposal */
159 proposal
->set_spi(proposal
, (u_int64_t
)this->me
.spi
);
161 iterator
->destroy(iterator
);
165 static status_t
install(private_child_sa_t
*this, proposal_t
*proposal
, prf_plus_t
*prf_plus
, bool mine
)
168 encryption_algorithm_t enc_algo
;
169 integrity_algorithm_t int_algo
;
170 chunk_t enc_key
, int_key
;
179 /* we must assign the roles to correctly set up the SAs */
183 dst
= this->other
.addr
;
188 src
= this->other
.addr
;
191 this->protocol
= proposal
->get_protocol(proposal
);
193 /* now we have to decide which spi to use. Use self allocated, if "mine",
194 * or the one in the proposal, if not "mine" (others). */
201 spi
= proposal
->get_spi(proposal
);
202 this->other
.spi
= spi
;
205 /* derive encryption key first */
206 if (proposal
->get_algorithm(proposal
, ENCRYPTION_ALGORITHM
, &algo
))
208 enc_algo
= algo
->algorithm
;
209 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "%s for %s: using %s %s, ",
210 mapping_find(protocol_id_m
, this->protocol
),
211 mine ?
"me" : "other",
212 mapping_find(transform_type_m
, ENCRYPTION_ALGORITHM
),
213 mapping_find(encryption_algorithm_m
, enc_algo
));
215 /* we must create a (unused) crypter, since its the only way to get the size
216 * of the key. This is not so nice, since charon must support all algorithms
217 * the kernel supports...
218 * TODO: build something of a encryption algorithm lookup function
220 crypter
= crypter_create(enc_algo
, algo
->key_size
);
221 key_size
= crypter
->get_key_size(crypter
);
222 crypter
->destroy(crypter
);
223 prf_plus
->allocate_bytes(prf_plus
, key_size
, &enc_key
);
224 this->logger
->log_chunk(this->logger
, PRIVATE
, "key:", enc_key
);
228 enc_algo
= ENCR_UNDEFINED
;
231 /* derive integrity key */
232 if (proposal
->get_algorithm(proposal
, INTEGRITY_ALGORITHM
, &algo
))
234 int_algo
= algo
->algorithm
;
235 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "%s for %s: using %s %s,",
236 mapping_find(protocol_id_m
, this->protocol
),
237 mine ?
"me" : "other",
238 mapping_find(transform_type_m
, INTEGRITY_ALGORITHM
),
239 mapping_find(integrity_algorithm_m
, algo
->algorithm
));
241 signer
= signer_create(int_algo
);
242 key_size
= signer
->get_key_size(signer
);
243 signer
->destroy(signer
);
244 prf_plus
->allocate_bytes(prf_plus
, key_size
, &int_key
);
245 this->logger
->log_chunk(this->logger
, PRIVATE
, "key:", int_key
);
249 int_algo
= AUTH_UNDEFINED
;
252 /* send keys down to kernel */
253 this->logger
->log(this->logger
, CONTROL
|LEVEL1
,
254 "installing 0x%.8x for %s, src %s dst %s",
255 ntohl(spi
), mapping_find(protocol_id_m
, this->protocol
),
256 src
->get_address(src
), dst
->get_address(dst
));
257 status
= charon
->kernel_interface
->add_sa(charon
->kernel_interface
,
261 mine ?
0 : this->soft_lifetime
,
264 int_algo
, int_key
, mine
);
266 if (enc_algo
!= ENCR_UNDEFINED
)
268 chunk_free(&enc_key
);
270 if (int_algo
!= AUTH_UNDEFINED
)
272 chunk_free(&int_key
);
277 static status_t
add(private_child_sa_t
*this, proposal_t
*proposal
, prf_plus_t
*prf_plus
)
281 /* install others (initiators) SAs*/
282 if (install(this, proposal
, prf_plus
, FALSE
) != SUCCESS
)
287 /* get SPIs for our SAs */
288 list
= linked_list_create();
289 list
->insert_last(list
, proposal
);
290 if (alloc(this, list
) != SUCCESS
)
297 /* install our (responders) SAs */
298 if (install(this, proposal
, prf_plus
, TRUE
) != SUCCESS
)
306 static status_t
update(private_child_sa_t
*this, proposal_t
*proposal
, prf_plus_t
*prf_plus
)
308 /* install our (initator) SAs */
309 if (install(this, proposal
, prf_plus
, TRUE
) != SUCCESS
)
313 /* install his (responder) SAs */
314 if (install(this, proposal
, prf_plus
, FALSE
) != SUCCESS
)
322 static status_t
add_policies(private_child_sa_t
*this, linked_list_t
*my_ts_list
, linked_list_t
*other_ts_list
)
324 iterator_t
*my_iter
, *other_iter
;
325 traffic_selector_t
*my_ts
, *other_ts
;
327 /* iterate over both lists */
328 my_iter
= my_ts_list
->create_iterator(my_ts_list
, TRUE
);
329 other_iter
= other_ts_list
->create_iterator(other_ts_list
, TRUE
);
330 while (my_iter
->has_next(my_iter
))
332 my_iter
->current(my_iter
, (void**)&my_ts
);
333 other_iter
->reset(other_iter
);
334 while (other_iter
->has_next(other_iter
))
336 /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
339 u_int16_t from_port
, to_port
;
343 other_iter
->current(other_iter
, (void**)&other_ts
);
345 /* only set up policies if protocol matches */
346 if (my_ts
->get_protocol(my_ts
) != other_ts
->get_protocol(other_ts
))
350 policy
= malloc_thing(sa_policy_t
);
351 policy
->upper_proto
= my_ts
->get_protocol(my_ts
);
353 /* calculate net and ports for local side */
354 family
= my_ts
->get_type(my_ts
) == TS_IPV4_ADDR_RANGE ? AF_INET
: AF_INET6
;
355 from_addr
= my_ts
->get_from_address(my_ts
);
356 from_port
= my_ts
->get_from_port(my_ts
);
357 to_port
= my_ts
->get_to_port(my_ts
);
358 from_port
= (from_port
!= to_port
) ?
0 : from_port
;
359 policy
->me
.net
= host_create_from_chunk(family
, from_addr
, from_port
);
360 policy
->me
.net_mask
= my_ts
->get_netmask(my_ts
);
361 chunk_free(&from_addr
);
363 /* calculate net and ports for remote side */
364 family
= other_ts
->get_type(other_ts
) == TS_IPV4_ADDR_RANGE ? AF_INET
: AF_INET6
;
365 from_addr
= other_ts
->get_from_address(other_ts
);
366 from_port
= other_ts
->get_from_port(other_ts
);
367 to_port
= other_ts
->get_to_port(other_ts
);
368 from_port
= (from_port
!= to_port
) ?
0 : from_port
;
369 policy
->other
.net
= host_create_from_chunk(family
, from_addr
, from_port
);
370 policy
->other
.net_mask
= other_ts
->get_netmask(other_ts
);
371 chunk_free(&from_addr
);
373 /* install 3 policies: out, in and forward */
374 status
= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
375 this->me
.addr
, this->other
.addr
,
376 policy
->me
.net
, policy
->other
.net
,
377 policy
->me
.net_mask
, policy
->other
.net_mask
,
378 XFRM_POLICY_OUT
, policy
->upper_proto
,
379 this->protocol
== PROTO_AH
,
380 this->protocol
== PROTO_ESP
,
383 status
|= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
384 this->other
.addr
, this->me
.addr
,
385 policy
->other
.net
, policy
->me
.net
,
386 policy
->other
.net_mask
, policy
->me
.net_mask
,
387 XFRM_POLICY_IN
, policy
->upper_proto
,
388 this->protocol
== PROTO_AH
,
389 this->protocol
== PROTO_ESP
,
392 status
|= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
393 this->other
.addr
, this->me
.addr
,
394 policy
->other
.net
, policy
->me
.net
,
395 policy
->other
.net_mask
, policy
->me
.net_mask
,
396 XFRM_POLICY_FWD
, policy
->upper_proto
,
397 this->protocol
== PROTO_AH
,
398 this->protocol
== PROTO_ESP
,
401 if (status
!= SUCCESS
)
403 my_iter
->destroy(my_iter
);
404 other_iter
->destroy(other_iter
);
405 policy
->me
.net
->destroy(policy
->me
.net
);
406 policy
->other
.net
->destroy(policy
->other
.net
);
411 /* add it to the policy list, since we want to know which policies we own */
412 this->policies
->insert_last(this->policies
, policy
);
415 my_iter
->destroy(my_iter
);
416 other_iter
->destroy(other_iter
);
421 * Implementation of child_sa_t.log_status.
423 static void log_status(private_child_sa_t
*this, logger_t
*logger
, char* name
)
425 iterator_t
*iterator
;
427 struct protoent
*proto
;
428 char proto_buf
[8] = "";
429 char *proto_name
= proto_buf
;
433 logger
= this->logger
;
435 logger
->log(logger
, CONTROL
|LEVEL1
, " \"%s\": protected with %s (0x%x/0x%x), reqid %d:",
437 this->protocol
== PROTO_ESP ?
"ESP" : "AH",
438 htonl(this->me
.spi
), htonl(this->other
.spi
),
440 iterator
= this->policies
->create_iterator(this->policies
, TRUE
);
441 while (iterator
->has_next(iterator
))
443 iterator
->current(iterator
, (void**)&policy
);
444 if (policy
->upper_proto
)
446 proto
= getprotobynumber(policy
->upper_proto
);
449 proto_name
= proto
->p_name
;
453 snprintf(proto_buf
, sizeof(proto_buf
), "<%d>", policy
->upper_proto
);
456 logger
->log(logger
, CONTROL
, " \"%s\": %s/%d==%s==%s/%d",
458 policy
->me
.net
->get_address(policy
->me
.net
), policy
->me
.net_mask
,
460 policy
->other
.net
->get_address(policy
->other
.net
), policy
->other
.net_mask
);
462 iterator
->destroy(iterator
);
466 * Implementation of child_sa_t.destroy.
468 static void destroy(private_child_sa_t
*this)
470 /* delete all policies in the kernel */
472 while (this->policies
->remove_last(this->policies
, (void**)&policy
) == SUCCESS
)
474 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
475 this->me
.addr
, this->other
.addr
,
476 policy
->me
.net
, policy
->other
.net
,
477 policy
->me
.net_mask
, policy
->other
.net_mask
,
478 XFRM_POLICY_OUT
, policy
->upper_proto
);
480 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
481 this->other
.addr
, this->me
.addr
,
482 policy
->other
.net
, policy
->me
.net
,
483 policy
->other
.net_mask
, policy
->me
.net_mask
,
484 XFRM_POLICY_IN
, policy
->upper_proto
);
486 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
487 this->other
.addr
, this->me
.addr
,
488 policy
->other
.net
, policy
->me
.net
,
489 policy
->other
.net_mask
, policy
->me
.net_mask
,
490 XFRM_POLICY_FWD
, policy
->upper_proto
);
492 policy
->me
.net
->destroy(policy
->me
.net
);
493 policy
->other
.net
->destroy(policy
->other
.net
);
496 this->policies
->destroy(this->policies
);
498 /* delete SAs in the kernel, if they are set up */
499 if (this->protocol
!= PROTO_NONE
)
501 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
502 this->other
.addr
, this->me
.spi
, this->protocol
);
503 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
504 this->me
.addr
, this->other
.spi
, this->protocol
);
510 * Described in header.
512 child_sa_t
* child_sa_create(host_t
*me
, host_t
* other
, u_int32_t soft_lifetime
, u_int32_t hard_lifetime
)
514 static u_int32_t reqid
= 2000000000;
515 private_child_sa_t
*this = malloc_thing(private_child_sa_t
);
517 /* public functions */
518 this->public.get_reqid
= (u_int32_t(*)(child_sa_t
*))get_reqid
;
519 this->public.get_spi
= (u_int32_t(*)(child_sa_t
*, bool))get_spi
;
520 this->public.get_protocol
= (protocol_id_t(*)(child_sa_t
*))get_protocol
;
521 this->public.alloc
= (status_t(*)(child_sa_t
*,linked_list_t
*))alloc
;
522 this->public.add
= (status_t(*)(child_sa_t
*,proposal_t
*,prf_plus_t
*))add
;
523 this->public.update
= (status_t(*)(child_sa_t
*,proposal_t
*,prf_plus_t
*))update
;
524 this->public.add_policies
= (status_t (*)(child_sa_t
*, linked_list_t
*,linked_list_t
*))add_policies
;
525 this->public.log_status
= (void (*)(child_sa_t
*, logger_t
*, char*))log_status
;
526 this->public.destroy
= (void(*)(child_sa_t
*))destroy
;
529 this->logger
= logger_manager
->get_logger(logger_manager
, CHILD_SA
);
531 this->other
.addr
= other
;
534 this->soft_lifetime
= soft_lifetime
;
535 this->hard_lifetime
= hard_lifetime
;
536 this->reqid
= ++reqid
;
537 this->policies
= linked_list_create();
538 this->protocol
= PROTO_NONE
;
540 return (&this->public);