2 * Copyright (C) 2012-2019 Tobias Brunner
3 * Copyright (C) 2005-2007 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * HSR 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
, has_proposal
, bool,
313 private_ike_cfg_t
*this, proposal_t
*match
, bool private)
315 enumerator_t
*enumerator
;
316 proposal_t
*proposal
;
318 enumerator
= this->proposals
->create_enumerator(this->proposals
);
319 while (enumerator
->enumerate(enumerator
, &proposal
))
321 if (proposal
->matches(proposal
, match
, private))
323 enumerator
->destroy(enumerator
);
327 enumerator
->destroy(enumerator
);
331 METHOD(ike_cfg_t
, select_proposal
, proposal_t
*,
332 private_ike_cfg_t
*this, linked_list_t
*proposals
, bool private,
335 enumerator_t
*prefer_enum
, *match_enum
;
336 proposal_t
*proposal
, *match
, *selected
= NULL
;
340 prefer_enum
= this->proposals
->create_enumerator(this->proposals
);
341 match_enum
= proposals
->create_enumerator(proposals
);
345 prefer_enum
= proposals
->create_enumerator(proposals
);
346 match_enum
= this->proposals
->create_enumerator(this->proposals
);
349 while (prefer_enum
->enumerate(prefer_enum
, (void**)&proposal
))
353 proposals
->reset_enumerator(proposals
, match_enum
);
357 this->proposals
->reset_enumerator(this->proposals
, match_enum
);
359 while (match_enum
->enumerate(match_enum
, (void**)&match
))
361 selected
= proposal
->select(proposal
, match
, prefer_self
, private);
364 DBG2(DBG_CFG
, "received proposals: %#P", proposals
);
365 DBG2(DBG_CFG
, "configured proposals: %#P", this->proposals
);
366 DBG1(DBG_CFG
, "selected proposal: %P", selected
);
375 prefer_enum
->destroy(prefer_enum
);
376 match_enum
->destroy(match_enum
);
379 DBG1(DBG_CFG
, "received proposals: %#P", proposals
);
380 DBG1(DBG_CFG
, "configured proposals: %#P", this->proposals
);
385 METHOD(ike_cfg_t
, get_dh_group
, diffie_hellman_group_t
,
386 private_ike_cfg_t
*this)
388 enumerator_t
*enumerator
;
389 proposal_t
*proposal
;
390 uint16_t dh_group
= MODP_NONE
;
392 enumerator
= this->proposals
->create_enumerator(this->proposals
);
393 while (enumerator
->enumerate(enumerator
, &proposal
))
395 if (proposal
->get_algorithm(proposal
, DIFFIE_HELLMAN_GROUP
, &dh_group
, NULL
))
400 enumerator
->destroy(enumerator
);
404 METHOD(ike_cfg_t
, equals
, bool,
405 private_ike_cfg_t
*this, ike_cfg_t
*other_public
)
407 private_ike_cfg_t
*other
= (private_ike_cfg_t
*)other_public
;
413 if (this->public.equals
!= other
->public.equals
)
417 if (!this->proposals
->equals_offset(this->proposals
, other
->proposals
,
418 offsetof(proposal_t
, equals
)))
423 this->version
== other
->version
&&
424 this->certreq
== other
->certreq
&&
425 this->force_encap
== other
->force_encap
&&
426 this->fragmentation
== other
->fragmentation
&&
427 streq(this->me
, other
->me
) &&
428 streq(this->other
, other
->other
) &&
429 this->my_port
== other
->my_port
&&
430 this->other_port
== other
->other_port
;
433 METHOD(ike_cfg_t
, get_ref
, ike_cfg_t
*,
434 private_ike_cfg_t
*this)
436 ref_get(&this->refcount
);
437 return &this->public;
440 METHOD(ike_cfg_t
, destroy
, void,
441 private_ike_cfg_t
*this)
443 if (ref_put(&this->refcount
))
445 this->proposals
->destroy_offset(this->proposals
,
446 offsetof(proposal_t
, destroy
));
449 this->my_hosts
->destroy_function(this->my_hosts
, free
);
450 this->other_hosts
->destroy_function(this->other_hosts
, free
);
451 this->my_ranges
->destroy_offset(this->my_ranges
,
452 offsetof(traffic_selector_t
, destroy
));
453 this->other_ranges
->destroy_offset(this->other_ranges
,
454 offsetof(traffic_selector_t
, destroy
));
460 * Try to parse a string as subnet
462 static traffic_selector_t
* make_subnet(char *str
)
466 pos
= strchr(str
, '/');
471 return traffic_selector_create_from_cidr(str
, 0, 0, 0);
475 * Try to parse a string as an IP range
477 static traffic_selector_t
* make_range(char *str
)
479 traffic_selector_t
*ts
;
483 if (!host_create_from_range(str
, &from
, &to
))
487 if (to
->get_family(to
) == AF_INET
)
489 type
= TS_IPV4_ADDR_RANGE
;
493 type
= TS_IPV6_ADDR_RANGE
;
495 ts
= traffic_selector_create_from_bytes(0, type
,
496 from
->get_address(from
), 0,
497 to
->get_address(to
), 0);
504 * Parse address string into lists of single hosts and ranges/subnets
506 static void parse_addresses(char *str
, linked_list_t
*hosts
,
507 linked_list_t
*ranges
)
509 enumerator_t
*enumerator
;
510 traffic_selector_t
*ts
;
512 enumerator
= enumerator_create_token(str
, ",", " ");
513 while (enumerator
->enumerate(enumerator
, &str
))
515 ts
= make_subnet(str
);
518 ranges
->insert_last(ranges
, ts
);
521 ts
= make_range(str
);
524 ranges
->insert_last(ranges
, ts
);
527 hosts
->insert_last(hosts
, strdup(str
));
529 enumerator
->destroy(enumerator
);
533 * Described in header.
535 int ike_cfg_get_family(ike_cfg_t
*cfg
, bool local
)
537 private_ike_cfg_t
*this = (private_ike_cfg_t
*)cfg
;
538 enumerator_t
*enumerator
;
541 int family
= AF_UNSPEC
;
545 enumerator
= this->my_hosts
->create_enumerator(this->my_hosts
);
549 enumerator
= this->other_hosts
->create_enumerator(this->other_hosts
);
551 while (enumerator
->enumerate(enumerator
, &str
))
553 if (streq(str
, "%any"))
554 { /* ignore %any as its family is undetermined */
557 host
= host_create_from_string(str
, 0);
560 if (family
== AF_UNSPEC
)
562 family
= host
->get_family(host
);
564 else if (family
!= host
->get_family(host
))
566 /* more than one address family defined */
574 enumerator
->destroy(enumerator
);
579 * Described in header.
581 bool ike_cfg_has_address(ike_cfg_t
*cfg
, host_t
*addr
, bool local
)
583 private_ike_cfg_t
*this = (private_ike_cfg_t
*)cfg
;
584 enumerator_t
*enumerator
;
591 enumerator
= this->my_hosts
->create_enumerator(this->my_hosts
);
595 enumerator
= this->other_hosts
->create_enumerator(this->other_hosts
);
597 while (enumerator
->enumerate(enumerator
, &str
))
599 host
= host_create_from_string(str
, 0);
600 if (host
&& addr
->ip_equals(addr
, host
))
608 enumerator
->destroy(enumerator
);
613 * Described in header
615 ike_cfg_t
*ike_cfg_create(ike_cfg_create_t
*data
)
617 private_ike_cfg_t
*this;
621 .get_version
= _get_version
,
622 .send_certreq
= _send_certreq
,
623 .force_encap
= _force_encap_
,
624 .fragmentation
= _fragmentation
,
625 .resolve_me
= _resolve_me
,
626 .resolve_other
= _resolve_other
,
627 .match_me
= _match_me
,
628 .match_other
= _match_other
,
629 .get_my_addr
= _get_my_addr
,
630 .get_other_addr
= _get_other_addr
,
631 .get_my_port
= _get_my_port
,
632 .get_other_port
= _get_other_port
,
633 .get_dscp
= _get_dscp
,
634 .add_proposal
= _add_proposal
,
635 .get_proposals
= _get_proposals
,
636 .select_proposal
= _select_proposal
,
637 .has_proposal
= _has_proposal
,
638 .get_dh_group
= _get_dh_group
,
644 .version
= data
->version
,
645 .certreq
= !data
->no_certreq
,
646 .force_encap
= data
->force_encap
,
647 .fragmentation
= data
->fragmentation
,
648 .me
= strdup(data
->local
),
649 .my_ranges
= linked_list_create(),
650 .my_hosts
= linked_list_create(),
651 .other
= strdup(data
->remote
),
652 .other_ranges
= linked_list_create(),
653 .other_hosts
= linked_list_create(),
654 .my_port
= data
->local_port
,
655 .other_port
= data
->remote_port
,
657 .proposals
= linked_list_create(),
660 parse_addresses(data
->local
, this->my_hosts
, this->my_ranges
);
661 parse_addresses(data
->remote
, this->other_hosts
, this->other_ranges
);
663 return &this->public;