2 * Copyright (C) 2005-2007 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #define _GNU_SOURCE /* for stdndup() */
24 ENUM(ike_version_names
, IKE_ANY
, IKEV2
,
30 typedef struct private_ike_cfg_t private_ike_cfg_t
;
33 * Private data of an ike_cfg_t object
35 struct private_ike_cfg_t
{
43 * Number of references hold by others to this ike_cfg
50 ike_version_t version
;
53 * Address list string for local host
58 * Address list string for remote host
63 * Local single host or DNS names, as allocated char*
65 linked_list_t
*my_hosts
;
68 * Remote single host or DNS names, as allocated char*
70 linked_list_t
*other_hosts
;
73 * Local ranges/subnets this config matches to, as traffic_selector_t*
75 linked_list_t
*my_ranges
;
78 * Remote ranges/subnets this config matches to, as traffic_selector_t*
80 linked_list_t
*other_ranges
;
93 * should we send a certificate request?
98 * enforce UDP encapsulation
103 * use IKEv1 fragmentation
105 fragmentation_t fragmentation
;
108 * DSCP value to use on sent IKE packets
113 * List of proposals to use
115 linked_list_t
*proposals
;
118 METHOD(ike_cfg_t
, get_version
, ike_version_t
,
119 private_ike_cfg_t
*this)
121 return this->version
;
124 METHOD(ike_cfg_t
, send_certreq
, bool,
125 private_ike_cfg_t
*this)
127 return this->certreq
;
130 METHOD(ike_cfg_t
, force_encap_
, bool,
131 private_ike_cfg_t
*this)
133 return this->force_encap
;
136 METHOD(ike_cfg_t
, fragmentation
, fragmentation_t
,
137 private_ike_cfg_t
*this)
139 return this->fragmentation
;
143 * Common function for resolve_me/other
145 static host_t
* resolve(linked_list_t
*hosts
, int family
, u_int16_t port
)
147 enumerator_t
*enumerator
;
152 enumerator
= hosts
->create_enumerator(hosts
);
153 while (enumerator
->enumerate(enumerator
, &str
))
155 host
= host_create_from_dns(str
, family
, port
);
162 enumerator
->destroy(enumerator
);
166 /* we have no single host configured, return %any */
167 host
= host_create_any(family
?: AF_INET
);
168 host
->set_port(host
, port
);
173 METHOD(ike_cfg_t
, resolve_me
, host_t
*,
174 private_ike_cfg_t
*this, int family
)
176 return resolve(this->my_hosts
, family
, this->my_port
);
179 METHOD(ike_cfg_t
, resolve_other
, host_t
*,
180 private_ike_cfg_t
*this, int family
)
182 return resolve(this->other_hosts
, family
, this->other_port
);
186 * Common function for match_me/other
188 static u_int
match(linked_list_t
*hosts
, linked_list_t
*ranges
, host_t
*cand
)
190 enumerator_t
*enumerator
;
191 traffic_selector_t
*ts
;
197 /* try single hosts first */
198 enumerator
= hosts
->create_enumerator(hosts
);
199 while (enumerator
->enumerate(enumerator
, &str
))
201 host
= host_create_from_dns(str
, cand
->get_family(cand
), 0);
204 if (host
->ip_equals(host
, cand
))
206 quality
= max(quality
, 128 + 1);
208 if (host
->is_anyaddr(host
))
210 quality
= max(quality
, 1);
215 enumerator
->destroy(enumerator
);
217 /* then ranges/subnets */
218 enumerator
= ranges
->create_enumerator(ranges
);
219 while (enumerator
->enumerate(enumerator
, &ts
))
221 if (ts
->includes(ts
, cand
))
223 if (ts
->to_subnet(ts
, &host
, &mask
))
225 quality
= max(quality
, mask
+ 1);
230 quality
= max(quality
, 1);
234 enumerator
->destroy(enumerator
);
239 METHOD(ike_cfg_t
, match_me
, u_int
,
240 private_ike_cfg_t
*this, host_t
*host
)
242 return match(this->my_hosts
, this->my_ranges
, host
);
245 METHOD(ike_cfg_t
, match_other
, u_int
,
246 private_ike_cfg_t
*this, host_t
*host
)
248 return match(this->other_hosts
, this->other_ranges
, host
);
251 METHOD(ike_cfg_t
, get_my_addr
, char*,
252 private_ike_cfg_t
*this)
257 METHOD(ike_cfg_t
, get_other_addr
, char*,
258 private_ike_cfg_t
*this)
263 METHOD(ike_cfg_t
, get_my_port
, u_int16_t
,
264 private_ike_cfg_t
*this)
266 return this->my_port
;
269 METHOD(ike_cfg_t
, get_other_port
, u_int16_t
,
270 private_ike_cfg_t
*this)
272 return this->other_port
;
275 METHOD(ike_cfg_t
, get_dscp
, u_int8_t
,
276 private_ike_cfg_t
*this)
281 METHOD(ike_cfg_t
, add_proposal
, void,
282 private_ike_cfg_t
*this, proposal_t
*proposal
)
284 this->proposals
->insert_last(this->proposals
, proposal
);
287 METHOD(ike_cfg_t
, get_proposals
, linked_list_t
*,
288 private_ike_cfg_t
*this)
290 enumerator_t
*enumerator
;
292 linked_list_t
*proposals
;
294 proposals
= linked_list_create();
295 enumerator
= this->proposals
->create_enumerator(this->proposals
);
296 while (enumerator
->enumerate(enumerator
, ¤t
))
298 current
= current
->clone(current
);
299 proposals
->insert_last(proposals
, current
);
301 enumerator
->destroy(enumerator
);
303 DBG2(DBG_CFG
, "configured proposals: %#P", proposals
);
308 METHOD(ike_cfg_t
, select_proposal
, proposal_t
*,
309 private_ike_cfg_t
*this, linked_list_t
*proposals
, bool private)
311 enumerator_t
*stored_enum
, *supplied_enum
;
312 proposal_t
*stored
, *supplied
, *selected
;
314 stored_enum
= this->proposals
->create_enumerator(this->proposals
);
315 supplied_enum
= proposals
->create_enumerator(proposals
);
318 /* compare all stored proposals with all supplied. Stored ones are preferred.*/
319 while (stored_enum
->enumerate(stored_enum
, (void**)&stored
))
321 proposals
->reset_enumerator(proposals
, supplied_enum
);
323 while (supplied_enum
->enumerate(supplied_enum
, (void**)&supplied
))
325 selected
= stored
->select(stored
, supplied
, private);
328 /* they match, return */
329 stored_enum
->destroy(stored_enum
);
330 supplied_enum
->destroy(supplied_enum
);
331 DBG2(DBG_CFG
, "received proposals: %#P", proposals
);
332 DBG2(DBG_CFG
, "configured proposals: %#P", this->proposals
);
333 DBG2(DBG_CFG
, "selected proposal: %P", selected
);
338 /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
339 stored_enum
->destroy(stored_enum
);
340 supplied_enum
->destroy(supplied_enum
);
341 DBG1(DBG_CFG
, "received proposals: %#P", proposals
);
342 DBG1(DBG_CFG
, "configured proposals: %#P", this->proposals
);
347 METHOD(ike_cfg_t
, get_dh_group
, diffie_hellman_group_t
,
348 private_ike_cfg_t
*this)
350 enumerator_t
*enumerator
;
351 proposal_t
*proposal
;
352 u_int16_t dh_group
= MODP_NONE
;
354 enumerator
= this->proposals
->create_enumerator(this->proposals
);
355 while (enumerator
->enumerate(enumerator
, &proposal
))
357 if (proposal
->get_algorithm(proposal
, DIFFIE_HELLMAN_GROUP
, &dh_group
, NULL
))
362 enumerator
->destroy(enumerator
);
366 METHOD(ike_cfg_t
, equals
, bool,
367 private_ike_cfg_t
*this, ike_cfg_t
*other_public
)
369 private_ike_cfg_t
*other
= (private_ike_cfg_t
*)other_public
;
370 enumerator_t
*e1
, *e2
;
378 if (this->public.equals
!= other
->public.equals
)
382 if (this->proposals
->get_count(this->proposals
) !=
383 other
->proposals
->get_count(other
->proposals
))
387 e1
= this->proposals
->create_enumerator(this->proposals
);
388 e2
= this->proposals
->create_enumerator(this->proposals
);
389 while (e1
->enumerate(e1
, &p1
) && e2
->enumerate(e2
, &p2
))
391 if (!p1
->equals(p1
, p2
))
401 this->version
== other
->version
&&
402 this->certreq
== other
->certreq
&&
403 this->force_encap
== other
->force_encap
&&
404 this->fragmentation
== other
->fragmentation
&&
405 streq(this->me
, other
->me
) &&
406 streq(this->other
, other
->other
) &&
407 this->my_port
== other
->my_port
&&
408 this->other_port
== other
->other_port
);
411 METHOD(ike_cfg_t
, get_ref
, ike_cfg_t
*,
412 private_ike_cfg_t
*this)
414 ref_get(&this->refcount
);
415 return &this->public;
418 METHOD(ike_cfg_t
, destroy
, void,
419 private_ike_cfg_t
*this)
421 if (ref_put(&this->refcount
))
423 this->proposals
->destroy_offset(this->proposals
,
424 offsetof(proposal_t
, destroy
));
427 this->my_hosts
->destroy_function(this->my_hosts
, free
);
428 this->other_hosts
->destroy_function(this->other_hosts
, free
);
429 this->my_ranges
->destroy_offset(this->my_ranges
,
430 offsetof(traffic_selector_t
, destroy
));
431 this->other_ranges
->destroy_offset(this->other_ranges
,
432 offsetof(traffic_selector_t
, destroy
));
438 * Try to parse a string as subnet
440 static traffic_selector_t
* make_subnet(char *str
)
444 pos
= strchr(str
, '/');
449 return traffic_selector_create_from_cidr(str
, 0, 0, 0);
453 * Try to parse a string as an IP range
455 static traffic_selector_t
* make_range(char *str
)
457 traffic_selector_t
*ts
;
462 pos
= strchr(str
, '-');
467 to
= host_create_from_string(pos
+ 1, 0);
472 str
= strndup(str
, pos
- str
);
473 from
= host_create_from_string_and_family(str
, to
->get_family(to
), 0);
480 if (to
->get_family(to
) == AF_INET
)
482 type
= TS_IPV4_ADDR_RANGE
;
486 type
= TS_IPV6_ADDR_RANGE
;
488 ts
= traffic_selector_create_from_bytes(0, type
,
489 from
->get_address(from
), 0,
490 to
->get_address(to
), 0);
497 * Parse address string into lists of single hosts and ranges/subnets
499 static void parse_addresses(char *str
, linked_list_t
*hosts
,
500 linked_list_t
*ranges
)
502 enumerator_t
*enumerator
;
503 traffic_selector_t
*ts
;
505 enumerator
= enumerator_create_token(str
, ",", " ");
506 while (enumerator
->enumerate(enumerator
, &str
))
508 ts
= make_subnet(str
);
511 ranges
->insert_last(ranges
, ts
);
514 ts
= make_range(str
);
517 ranges
->insert_last(ranges
, ts
);
520 hosts
->insert_last(hosts
, strdup(str
));
522 enumerator
->destroy(enumerator
);
526 * Described in header.
528 ike_cfg_t
*ike_cfg_create(ike_version_t version
, bool certreq
, bool force_encap
,
529 char *me
, u_int16_t my_port
,
530 char *other
, u_int16_t other_port
,
531 fragmentation_t fragmentation
, u_int8_t dscp
)
533 private_ike_cfg_t
*this;
537 .get_version
= _get_version
,
538 .send_certreq
= _send_certreq
,
539 .force_encap
= _force_encap_
,
540 .fragmentation
= _fragmentation
,
541 .resolve_me
= _resolve_me
,
542 .resolve_other
= _resolve_other
,
543 .match_me
= _match_me
,
544 .match_other
= _match_other
,
545 .get_my_addr
= _get_my_addr
,
546 .get_other_addr
= _get_other_addr
,
547 .get_my_port
= _get_my_port
,
548 .get_other_port
= _get_other_port
,
549 .get_dscp
= _get_dscp
,
550 .add_proposal
= _add_proposal
,
551 .get_proposals
= _get_proposals
,
552 .select_proposal
= _select_proposal
,
553 .get_dh_group
= _get_dh_group
,
561 .force_encap
= force_encap
,
562 .fragmentation
= fragmentation
,
564 .my_ranges
= linked_list_create(),
565 .my_hosts
= linked_list_create(),
566 .other
= strdup(other
),
567 .other_ranges
= linked_list_create(),
568 .other_hosts
= linked_list_create(),
570 .other_port
= other_port
,
572 .proposals
= linked_list_create(),
575 parse_addresses(me
, this->my_hosts
, this->my_ranges
);
576 parse_addresses(other
, this->other_hosts
, this->other_ranges
);
578 return &this->public;