2 * Copyright (C) 2012-2017 Tobias Brunner
3 * Copyright (C) 2005-2007 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #define _GNU_SOURCE /* for stdndup() */
25 ENUM(ike_version_names
, IKE_ANY
, IKEV2
,
31 typedef struct private_ike_cfg_t private_ike_cfg_t
;
34 * Private data of an ike_cfg_t object
36 struct private_ike_cfg_t
{
44 * Number of references hold by others to this ike_cfg
51 ike_version_t version
;
54 * Address list string for local host
59 * Address list string for remote host
64 * Local single host or DNS names, as allocated char*
66 linked_list_t
*my_hosts
;
69 * Remote single host or DNS names, as allocated char*
71 linked_list_t
*other_hosts
;
74 * Local ranges/subnets this config matches to, as traffic_selector_t*
76 linked_list_t
*my_ranges
;
79 * Remote ranges/subnets this config matches to, as traffic_selector_t*
81 linked_list_t
*other_ranges
;
94 * should we send a certificate request?
99 * enforce UDP encapsulation
104 * use IKEv1 fragmentation
106 fragmentation_t fragmentation
;
109 * DSCP value to use on sent IKE packets
114 * List of proposals to use
116 linked_list_t
*proposals
;
119 METHOD(ike_cfg_t
, get_version
, ike_version_t
,
120 private_ike_cfg_t
*this)
122 return this->version
;
125 METHOD(ike_cfg_t
, send_certreq
, bool,
126 private_ike_cfg_t
*this)
128 return this->certreq
;
131 METHOD(ike_cfg_t
, force_encap_
, bool,
132 private_ike_cfg_t
*this)
134 return this->force_encap
;
137 METHOD(ike_cfg_t
, fragmentation
, fragmentation_t
,
138 private_ike_cfg_t
*this)
140 return this->fragmentation
;
144 * Common function for resolve_me/other
146 static host_t
* resolve(linked_list_t
*hosts
, int family
, uint16_t port
)
148 enumerator_t
*enumerator
;
153 enumerator
= hosts
->create_enumerator(hosts
);
154 while (enumerator
->enumerate(enumerator
, &str
))
156 host
= host_create_from_dns(str
, family
, port
);
163 enumerator
->destroy(enumerator
);
167 /* we have no single host configured, return %any */
168 host
= host_create_any(family
?: AF_INET
);
169 host
->set_port(host
, port
);
174 METHOD(ike_cfg_t
, resolve_me
, host_t
*,
175 private_ike_cfg_t
*this, int family
)
177 return resolve(this->my_hosts
, family
, this->my_port
);
180 METHOD(ike_cfg_t
, resolve_other
, host_t
*,
181 private_ike_cfg_t
*this, int family
)
183 return resolve(this->other_hosts
, family
, this->other_port
);
187 * Common function for match_me/other
189 static u_int
match(linked_list_t
*hosts
, linked_list_t
*ranges
, host_t
*cand
)
191 enumerator_t
*enumerator
;
192 traffic_selector_t
*ts
;
198 /* try single hosts first */
199 enumerator
= hosts
->create_enumerator(hosts
);
200 while (enumerator
->enumerate(enumerator
, &str
))
202 host
= host_create_from_dns(str
, cand
->get_family(cand
), 0);
205 if (host
->ip_equals(host
, cand
))
207 quality
= max(quality
, 128 + 1);
209 if (host
->is_anyaddr(host
))
211 quality
= max(quality
, 1);
216 enumerator
->destroy(enumerator
);
218 /* then ranges/subnets */
219 enumerator
= ranges
->create_enumerator(ranges
);
220 while (enumerator
->enumerate(enumerator
, &ts
))
222 if (ts
->includes(ts
, cand
))
224 if (ts
->to_subnet(ts
, &host
, &mask
))
226 quality
= max(quality
, mask
+ 1);
230 quality
= max(quality
, 1);
235 enumerator
->destroy(enumerator
);
240 METHOD(ike_cfg_t
, match_me
, u_int
,
241 private_ike_cfg_t
*this, host_t
*host
)
243 return match(this->my_hosts
, this->my_ranges
, host
);
246 METHOD(ike_cfg_t
, match_other
, u_int
,
247 private_ike_cfg_t
*this, host_t
*host
)
249 return match(this->other_hosts
, this->other_ranges
, host
);
252 METHOD(ike_cfg_t
, get_my_addr
, char*,
253 private_ike_cfg_t
*this)
258 METHOD(ike_cfg_t
, get_other_addr
, char*,
259 private_ike_cfg_t
*this)
264 METHOD(ike_cfg_t
, get_my_port
, uint16_t,
265 private_ike_cfg_t
*this)
267 return this->my_port
;
270 METHOD(ike_cfg_t
, get_other_port
, uint16_t,
271 private_ike_cfg_t
*this)
273 return this->other_port
;
276 METHOD(ike_cfg_t
, get_dscp
, uint8_t,
277 private_ike_cfg_t
*this)
282 METHOD(ike_cfg_t
, add_proposal
, void,
283 private_ike_cfg_t
*this, proposal_t
*proposal
)
287 this->proposals
->insert_last(this->proposals
, proposal
);
291 METHOD(ike_cfg_t
, get_proposals
, linked_list_t
*,
292 private_ike_cfg_t
*this)
294 enumerator_t
*enumerator
;
296 linked_list_t
*proposals
;
298 proposals
= linked_list_create();
299 enumerator
= this->proposals
->create_enumerator(this->proposals
);
300 while (enumerator
->enumerate(enumerator
, ¤t
))
302 current
= current
->clone(current
);
303 proposals
->insert_last(proposals
, current
);
305 enumerator
->destroy(enumerator
);
307 DBG2(DBG_CFG
, "configured proposals: %#P", proposals
);
312 METHOD(ike_cfg_t
, select_proposal
, proposal_t
*,
313 private_ike_cfg_t
*this, linked_list_t
*proposals
, bool private,
316 enumerator_t
*prefer_enum
, *match_enum
;
317 proposal_t
*proposal
, *match
, *selected
= NULL
;
321 prefer_enum
= this->proposals
->create_enumerator(this->proposals
);
322 match_enum
= proposals
->create_enumerator(proposals
);
326 prefer_enum
= proposals
->create_enumerator(proposals
);
327 match_enum
= this->proposals
->create_enumerator(this->proposals
);
330 while (prefer_enum
->enumerate(prefer_enum
, (void**)&proposal
))
334 proposals
->reset_enumerator(proposals
, match_enum
);
338 this->proposals
->reset_enumerator(this->proposals
, match_enum
);
340 while (match_enum
->enumerate(match_enum
, (void**)&match
))
342 selected
= proposal
->select(proposal
, match
, prefer_self
, private);
345 DBG2(DBG_CFG
, "received proposals: %#P", proposals
);
346 DBG2(DBG_CFG
, "configured proposals: %#P", this->proposals
);
347 DBG2(DBG_CFG
, "selected proposal: %P", selected
);
356 prefer_enum
->destroy(prefer_enum
);
357 match_enum
->destroy(match_enum
);
360 DBG1(DBG_CFG
, "received proposals: %#P", proposals
);
361 DBG1(DBG_CFG
, "configured proposals: %#P", this->proposals
);
366 METHOD(ike_cfg_t
, get_dh_group
, diffie_hellman_group_t
,
367 private_ike_cfg_t
*this)
369 enumerator_t
*enumerator
;
370 proposal_t
*proposal
;
371 uint16_t dh_group
= MODP_NONE
;
373 enumerator
= this->proposals
->create_enumerator(this->proposals
);
374 while (enumerator
->enumerate(enumerator
, &proposal
))
376 if (proposal
->get_algorithm(proposal
, DIFFIE_HELLMAN_GROUP
, &dh_group
, NULL
))
381 enumerator
->destroy(enumerator
);
385 METHOD(ike_cfg_t
, equals
, bool,
386 private_ike_cfg_t
*this, ike_cfg_t
*other_public
)
388 private_ike_cfg_t
*other
= (private_ike_cfg_t
*)other_public
;
394 if (this->public.equals
!= other
->public.equals
)
398 if (!this->proposals
->equals_offset(this->proposals
, other
->proposals
,
399 offsetof(proposal_t
, equals
)))
404 this->version
== other
->version
&&
405 this->certreq
== other
->certreq
&&
406 this->force_encap
== other
->force_encap
&&
407 this->fragmentation
== other
->fragmentation
&&
408 streq(this->me
, other
->me
) &&
409 streq(this->other
, other
->other
) &&
410 this->my_port
== other
->my_port
&&
411 this->other_port
== other
->other_port
;
414 METHOD(ike_cfg_t
, get_ref
, ike_cfg_t
*,
415 private_ike_cfg_t
*this)
417 ref_get(&this->refcount
);
418 return &this->public;
421 METHOD(ike_cfg_t
, destroy
, void,
422 private_ike_cfg_t
*this)
424 if (ref_put(&this->refcount
))
426 this->proposals
->destroy_offset(this->proposals
,
427 offsetof(proposal_t
, destroy
));
430 this->my_hosts
->destroy_function(this->my_hosts
, free
);
431 this->other_hosts
->destroy_function(this->other_hosts
, free
);
432 this->my_ranges
->destroy_offset(this->my_ranges
,
433 offsetof(traffic_selector_t
, destroy
));
434 this->other_ranges
->destroy_offset(this->other_ranges
,
435 offsetof(traffic_selector_t
, destroy
));
441 * Try to parse a string as subnet
443 static traffic_selector_t
* make_subnet(char *str
)
447 pos
= strchr(str
, '/');
452 return traffic_selector_create_from_cidr(str
, 0, 0, 0);
456 * Try to parse a string as an IP range
458 static traffic_selector_t
* make_range(char *str
)
460 traffic_selector_t
*ts
;
464 if (!host_create_from_range(str
, &from
, &to
))
468 if (to
->get_family(to
) == AF_INET
)
470 type
= TS_IPV4_ADDR_RANGE
;
474 type
= TS_IPV6_ADDR_RANGE
;
476 ts
= traffic_selector_create_from_bytes(0, type
,
477 from
->get_address(from
), 0,
478 to
->get_address(to
), 0);
485 * Parse address string into lists of single hosts and ranges/subnets
487 static void parse_addresses(char *str
, linked_list_t
*hosts
,
488 linked_list_t
*ranges
)
490 enumerator_t
*enumerator
;
491 traffic_selector_t
*ts
;
493 enumerator
= enumerator_create_token(str
, ",", " ");
494 while (enumerator
->enumerate(enumerator
, &str
))
496 ts
= make_subnet(str
);
499 ranges
->insert_last(ranges
, ts
);
502 ts
= make_range(str
);
505 ranges
->insert_last(ranges
, ts
);
508 hosts
->insert_last(hosts
, strdup(str
));
510 enumerator
->destroy(enumerator
);
514 * Described in header.
516 int ike_cfg_get_family(ike_cfg_t
*cfg
, bool local
)
518 private_ike_cfg_t
*this = (private_ike_cfg_t
*)cfg
;
519 enumerator_t
*enumerator
;
522 int family
= AF_UNSPEC
;
526 enumerator
= this->my_hosts
->create_enumerator(this->my_hosts
);
530 enumerator
= this->other_hosts
->create_enumerator(this->other_hosts
);
532 while (enumerator
->enumerate(enumerator
, &str
))
534 if (streq(str
, "%any"))
535 { /* ignore %any as its family is undetermined */
538 host
= host_create_from_string(str
, 0);
541 if (family
== AF_UNSPEC
)
543 family
= host
->get_family(host
);
545 else if (family
!= host
->get_family(host
))
547 /* more than one address family defined */
555 enumerator
->destroy(enumerator
);
560 * Described in header.
562 bool ike_cfg_has_address(ike_cfg_t
*cfg
, host_t
*addr
, bool local
)
564 private_ike_cfg_t
*this = (private_ike_cfg_t
*)cfg
;
565 enumerator_t
*enumerator
;
572 enumerator
= this->my_hosts
->create_enumerator(this->my_hosts
);
576 enumerator
= this->other_hosts
->create_enumerator(this->other_hosts
);
578 while (enumerator
->enumerate(enumerator
, &str
))
580 host
= host_create_from_string(str
, 0);
581 if (host
&& addr
->ip_equals(addr
, host
))
589 enumerator
->destroy(enumerator
);
594 * Described in header.
596 ike_cfg_t
*ike_cfg_create(ike_version_t version
, bool certreq
, bool force_encap
,
597 char *me
, uint16_t my_port
,
598 char *other
, uint16_t other_port
,
599 fragmentation_t fragmentation
, uint8_t dscp
)
601 private_ike_cfg_t
*this;
605 .get_version
= _get_version
,
606 .send_certreq
= _send_certreq
,
607 .force_encap
= _force_encap_
,
608 .fragmentation
= _fragmentation
,
609 .resolve_me
= _resolve_me
,
610 .resolve_other
= _resolve_other
,
611 .match_me
= _match_me
,
612 .match_other
= _match_other
,
613 .get_my_addr
= _get_my_addr
,
614 .get_other_addr
= _get_other_addr
,
615 .get_my_port
= _get_my_port
,
616 .get_other_port
= _get_other_port
,
617 .get_dscp
= _get_dscp
,
618 .add_proposal
= _add_proposal
,
619 .get_proposals
= _get_proposals
,
620 .select_proposal
= _select_proposal
,
621 .get_dh_group
= _get_dh_group
,
629 .force_encap
= force_encap
,
630 .fragmentation
= fragmentation
,
632 .my_ranges
= linked_list_create(),
633 .my_hosts
= linked_list_create(),
634 .other
= strdup(other
),
635 .other_ranges
= linked_list_create(),
636 .other_hosts
= linked_list_create(),
638 .other_port
= other_port
,
640 .proposals
= linked_list_create(),
643 parse_addresses(me
, this->my_hosts
, this->my_ranges
);
644 parse_addresses(other
, this->other_hosts
, this->other_ranges
);
646 return &this->public;