proposal: Add selection flags to clone() method
[strongswan.git] / src / libcharon / config / ike_cfg.c
1 /*
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
6 *
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>.
11 *
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
15 * for more details.
16 */
17
18 #define _GNU_SOURCE /* for stdndup() */
19 #include <string.h>
20
21 #include "ike_cfg.h"
22
23 #include <daemon.h>
24
25 ENUM(ike_version_names, IKE_ANY, IKEV2,
26 "IKEv1/2",
27 "IKEv1",
28 "IKEv2",
29 );
30
31 typedef struct private_ike_cfg_t private_ike_cfg_t;
32
33 /**
34 * Private data of an ike_cfg_t object
35 */
36 struct private_ike_cfg_t {
37
38 /**
39 * Public part
40 */
41 ike_cfg_t public;
42
43 /**
44 * Number of references hold by others to this ike_cfg
45 */
46 refcount_t refcount;
47
48 /**
49 * IKE version to use
50 */
51 ike_version_t version;
52
53 /**
54 * Address list string for local host
55 */
56 char *me;
57
58 /**
59 * Address list string for remote host
60 */
61 char *other;
62
63 /**
64 * Local single host or DNS names, as allocated char*
65 */
66 linked_list_t *my_hosts;
67
68 /**
69 * Remote single host or DNS names, as allocated char*
70 */
71 linked_list_t *other_hosts;
72
73 /**
74 * Local ranges/subnets this config matches to, as traffic_selector_t*
75 */
76 linked_list_t *my_ranges;
77
78 /**
79 * Remote ranges/subnets this config matches to, as traffic_selector_t*
80 */
81 linked_list_t *other_ranges;
82
83 /**
84 * our source port
85 */
86 uint16_t my_port;
87
88 /**
89 * destination port
90 */
91 uint16_t other_port;
92
93 /**
94 * should we send a certificate request?
95 */
96 bool certreq;
97
98 /**
99 * enforce UDP encapsulation
100 */
101 bool force_encap;
102
103 /**
104 * use IKE fragmentation
105 */
106 fragmentation_t fragmentation;
107
108 /**
109 * childless IKE_SAs
110 */
111 childless_t childless;
112
113 /**
114 * DSCP value to use on sent IKE packets
115 */
116 uint8_t dscp;
117
118 /**
119 * List of proposals to use
120 */
121 linked_list_t *proposals;
122 };
123
124 METHOD(ike_cfg_t, get_version, ike_version_t,
125 private_ike_cfg_t *this)
126 {
127 return this->version;
128 }
129
130 METHOD(ike_cfg_t, send_certreq, bool,
131 private_ike_cfg_t *this)
132 {
133 return this->certreq;
134 }
135
136 METHOD(ike_cfg_t, force_encap_, bool,
137 private_ike_cfg_t *this)
138 {
139 return this->force_encap;
140 }
141
142 METHOD(ike_cfg_t, fragmentation, fragmentation_t,
143 private_ike_cfg_t *this)
144 {
145 return this->fragmentation;
146 }
147
148 METHOD(ike_cfg_t, childless, childless_t,
149 private_ike_cfg_t *this)
150 {
151 return this->childless;
152 }
153
154 /**
155 * Common function for resolve_me/other
156 */
157 static host_t* resolve(linked_list_t *hosts, int family, uint16_t port)
158 {
159 enumerator_t *enumerator;
160 host_t *host = NULL;
161 bool tried = FALSE;
162 char *str;
163
164 enumerator = hosts->create_enumerator(hosts);
165 while (enumerator->enumerate(enumerator, &str))
166 {
167 host = host_create_from_dns(str, family, port);
168 if (host)
169 {
170 break;
171 }
172 tried = TRUE;
173 }
174 enumerator->destroy(enumerator);
175
176 if (!host && !tried)
177 {
178 /* we have no single host configured, return %any */
179 host = host_create_any(family ?: AF_INET);
180 host->set_port(host, port);
181 }
182 return host;
183 }
184
185 METHOD(ike_cfg_t, resolve_me, host_t*,
186 private_ike_cfg_t *this, int family)
187 {
188 return resolve(this->my_hosts, family, this->my_port);
189 }
190
191 METHOD(ike_cfg_t, resolve_other, host_t*,
192 private_ike_cfg_t *this, int family)
193 {
194 return resolve(this->other_hosts, family, this->other_port);
195 }
196
197 /**
198 * Common function for match_me/other
199 */
200 static u_int match(linked_list_t *hosts, linked_list_t *ranges, host_t *cand)
201 {
202 enumerator_t *enumerator;
203 traffic_selector_t *ts;
204 char *str;
205 host_t *host;
206 uint8_t mask;
207 u_int quality = 0;
208
209 /* try single hosts first */
210 enumerator = hosts->create_enumerator(hosts);
211 while (enumerator->enumerate(enumerator, &str))
212 {
213 host = host_create_from_dns(str, cand->get_family(cand), 0);
214 if (host)
215 {
216 if (host->ip_equals(host, cand))
217 {
218 quality = max(quality, 128 + 1);
219 }
220 if (host->is_anyaddr(host))
221 {
222 quality = max(quality, 1);
223 }
224 host->destroy(host);
225 }
226 }
227 enumerator->destroy(enumerator);
228
229 /* then ranges/subnets */
230 enumerator = ranges->create_enumerator(ranges);
231 while (enumerator->enumerate(enumerator, &ts))
232 {
233 if (ts->includes(ts, cand))
234 {
235 if (ts->to_subnet(ts, &host, &mask))
236 {
237 quality = max(quality, mask + 1);
238 }
239 else
240 {
241 quality = max(quality, 1);
242 }
243 host->destroy(host);
244 }
245 }
246 enumerator->destroy(enumerator);
247
248 return quality;
249 }
250
251 METHOD(ike_cfg_t, match_me, u_int,
252 private_ike_cfg_t *this, host_t *host)
253 {
254 return match(this->my_hosts, this->my_ranges, host);
255 }
256
257 METHOD(ike_cfg_t, match_other, u_int,
258 private_ike_cfg_t *this, host_t *host)
259 {
260 return match(this->other_hosts, this->other_ranges, host);
261 }
262
263 METHOD(ike_cfg_t, get_my_addr, char*,
264 private_ike_cfg_t *this)
265 {
266 return this->me;
267 }
268
269 METHOD(ike_cfg_t, get_other_addr, char*,
270 private_ike_cfg_t *this)
271 {
272 return this->other;
273 }
274
275 METHOD(ike_cfg_t, get_my_port, uint16_t,
276 private_ike_cfg_t *this)
277 {
278 return this->my_port;
279 }
280
281 METHOD(ike_cfg_t, get_other_port, uint16_t,
282 private_ike_cfg_t *this)
283 {
284 return this->other_port;
285 }
286
287 METHOD(ike_cfg_t, get_dscp, uint8_t,
288 private_ike_cfg_t *this)
289 {
290 return this->dscp;
291 }
292
293 METHOD(ike_cfg_t, add_proposal, void,
294 private_ike_cfg_t *this, proposal_t *proposal)
295 {
296 if (proposal)
297 {
298 this->proposals->insert_last(this->proposals, proposal);
299 }
300 }
301
302 METHOD(ike_cfg_t, get_proposals, linked_list_t*,
303 private_ike_cfg_t *this)
304 {
305 enumerator_t *enumerator;
306 proposal_t *current;
307 linked_list_t *proposals;
308
309 proposals = linked_list_create();
310 enumerator = this->proposals->create_enumerator(this->proposals);
311 while (enumerator->enumerate(enumerator, &current))
312 {
313 current = current->clone(current, 0);
314 proposals->insert_last(proposals, current);
315 }
316 enumerator->destroy(enumerator);
317
318 DBG2(DBG_CFG, "configured proposals: %#P", proposals);
319
320 return proposals;
321 }
322
323 METHOD(ike_cfg_t, has_proposal, bool,
324 private_ike_cfg_t *this, proposal_t *match, bool private)
325 {
326 enumerator_t *enumerator;
327 proposal_t *proposal;
328
329 enumerator = this->proposals->create_enumerator(this->proposals);
330 while (enumerator->enumerate(enumerator, &proposal))
331 {
332 if (proposal->matches(proposal, match,
333 private ? 0 : PROPOSAL_SKIP_PRIVATE))
334 {
335 enumerator->destroy(enumerator);
336 return TRUE;
337 }
338 }
339 enumerator->destroy(enumerator);
340 return FALSE;
341 }
342
343 METHOD(ike_cfg_t, select_proposal, proposal_t*,
344 private_ike_cfg_t *this, linked_list_t *proposals,
345 proposal_selection_flag_t flags)
346 {
347 return proposal_select(this->proposals, proposals, flags);
348 }
349
350 METHOD(ike_cfg_t, get_dh_group, diffie_hellman_group_t,
351 private_ike_cfg_t *this)
352 {
353 enumerator_t *enumerator;
354 proposal_t *proposal;
355 uint16_t dh_group = MODP_NONE;
356
357 enumerator = this->proposals->create_enumerator(this->proposals);
358 while (enumerator->enumerate(enumerator, &proposal))
359 {
360 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
361 {
362 break;
363 }
364 }
365 enumerator->destroy(enumerator);
366 return dh_group;
367 }
368
369 METHOD(ike_cfg_t, equals, bool,
370 private_ike_cfg_t *this, ike_cfg_t *other_public)
371 {
372 private_ike_cfg_t *other = (private_ike_cfg_t*)other_public;
373
374 if (this == other)
375 {
376 return TRUE;
377 }
378 if (this->public.equals != other->public.equals)
379 {
380 return FALSE;
381 }
382 if (!this->proposals->equals_offset(this->proposals, other->proposals,
383 offsetof(proposal_t, equals)))
384 {
385 return FALSE;
386 }
387 return
388 this->version == other->version &&
389 this->certreq == other->certreq &&
390 this->force_encap == other->force_encap &&
391 this->fragmentation == other->fragmentation &&
392 this->childless == other->childless &&
393 streq(this->me, other->me) &&
394 streq(this->other, other->other) &&
395 this->my_port == other->my_port &&
396 this->other_port == other->other_port;
397 }
398
399 METHOD(ike_cfg_t, get_ref, ike_cfg_t*,
400 private_ike_cfg_t *this)
401 {
402 ref_get(&this->refcount);
403 return &this->public;
404 }
405
406 METHOD(ike_cfg_t, destroy, void,
407 private_ike_cfg_t *this)
408 {
409 if (ref_put(&this->refcount))
410 {
411 this->proposals->destroy_offset(this->proposals,
412 offsetof(proposal_t, destroy));
413 free(this->me);
414 free(this->other);
415 this->my_hosts->destroy_function(this->my_hosts, free);
416 this->other_hosts->destroy_function(this->other_hosts, free);
417 this->my_ranges->destroy_offset(this->my_ranges,
418 offsetof(traffic_selector_t, destroy));
419 this->other_ranges->destroy_offset(this->other_ranges,
420 offsetof(traffic_selector_t, destroy));
421 free(this);
422 }
423 }
424
425 /**
426 * Try to parse a string as subnet
427 */
428 static traffic_selector_t* make_subnet(char *str)
429 {
430 char *pos;
431
432 pos = strchr(str, '/');
433 if (!pos)
434 {
435 return NULL;
436 }
437 return traffic_selector_create_from_cidr(str, 0, 0, 0);
438 }
439
440 /**
441 * Try to parse a string as an IP range
442 */
443 static traffic_selector_t* make_range(char *str)
444 {
445 traffic_selector_t *ts;
446 ts_type_t type;
447 host_t *from, *to;
448
449 if (!host_create_from_range(str, &from, &to))
450 {
451 return NULL;
452 }
453 if (to->get_family(to) == AF_INET)
454 {
455 type = TS_IPV4_ADDR_RANGE;
456 }
457 else
458 {
459 type = TS_IPV6_ADDR_RANGE;
460 }
461 ts = traffic_selector_create_from_bytes(0, type,
462 from->get_address(from), 0,
463 to->get_address(to), 0);
464 from->destroy(from);
465 to->destroy(to);
466 return ts;
467 }
468
469 /**
470 * Parse address string into lists of single hosts and ranges/subnets
471 */
472 static void parse_addresses(char *str, linked_list_t *hosts,
473 linked_list_t *ranges)
474 {
475 enumerator_t *enumerator;
476 traffic_selector_t *ts;
477
478 enumerator = enumerator_create_token(str, ",", " ");
479 while (enumerator->enumerate(enumerator, &str))
480 {
481 ts = make_subnet(str);
482 if (ts)
483 {
484 ranges->insert_last(ranges, ts);
485 continue;
486 }
487 ts = make_range(str);
488 if (ts)
489 {
490 ranges->insert_last(ranges, ts);
491 continue;
492 }
493 hosts->insert_last(hosts, strdup(str));
494 }
495 enumerator->destroy(enumerator);
496 }
497
498 /**
499 * Described in header.
500 */
501 int ike_cfg_get_family(ike_cfg_t *cfg, bool local)
502 {
503 private_ike_cfg_t *this = (private_ike_cfg_t*)cfg;
504 enumerator_t *enumerator;
505 host_t *host;
506 char *str;
507 int family = AF_UNSPEC;
508
509 if (local)
510 {
511 enumerator = this->my_hosts->create_enumerator(this->my_hosts);
512 }
513 else
514 {
515 enumerator = this->other_hosts->create_enumerator(this->other_hosts);
516 }
517 while (enumerator->enumerate(enumerator, &str))
518 {
519 if (streq(str, "%any"))
520 { /* ignore %any as its family is undetermined */
521 continue;
522 }
523 host = host_create_from_string(str, 0);
524 if (host)
525 {
526 if (family == AF_UNSPEC)
527 {
528 family = host->get_family(host);
529 }
530 else if (family != host->get_family(host))
531 {
532 /* more than one address family defined */
533 family = AF_UNSPEC;
534 host->destroy(host);
535 break;
536 }
537 }
538 DESTROY_IF(host);
539 }
540 enumerator->destroy(enumerator);
541 return family;
542 }
543
544 /**
545 * Described in header.
546 */
547 bool ike_cfg_has_address(ike_cfg_t *cfg, host_t *addr, bool local)
548 {
549 private_ike_cfg_t *this = (private_ike_cfg_t*)cfg;
550 enumerator_t *enumerator;
551 host_t *host;
552 char *str;
553 bool found = FALSE;
554
555 if (local)
556 {
557 enumerator = this->my_hosts->create_enumerator(this->my_hosts);
558 }
559 else
560 {
561 enumerator = this->other_hosts->create_enumerator(this->other_hosts);
562 }
563 while (enumerator->enumerate(enumerator, &str))
564 {
565 host = host_create_from_string(str, 0);
566 if (host && addr->ip_equals(addr, host))
567 {
568 host->destroy(host);
569 found = TRUE;
570 break;
571 }
572 DESTROY_IF(host);
573 }
574 enumerator->destroy(enumerator);
575 return found;
576 }
577
578 /*
579 * Described in header
580 */
581 ike_cfg_t *ike_cfg_create(ike_cfg_create_t *data)
582 {
583 private_ike_cfg_t *this;
584
585 INIT(this,
586 .public = {
587 .get_version = _get_version,
588 .send_certreq = _send_certreq,
589 .force_encap = _force_encap_,
590 .fragmentation = _fragmentation,
591 .childless = _childless,
592 .resolve_me = _resolve_me,
593 .resolve_other = _resolve_other,
594 .match_me = _match_me,
595 .match_other = _match_other,
596 .get_my_addr = _get_my_addr,
597 .get_other_addr = _get_other_addr,
598 .get_my_port = _get_my_port,
599 .get_other_port = _get_other_port,
600 .get_dscp = _get_dscp,
601 .add_proposal = _add_proposal,
602 .get_proposals = _get_proposals,
603 .select_proposal = _select_proposal,
604 .has_proposal = _has_proposal,
605 .get_dh_group = _get_dh_group,
606 .equals = _equals,
607 .get_ref = _get_ref,
608 .destroy = _destroy,
609 },
610 .refcount = 1,
611 .version = data->version,
612 .certreq = !data->no_certreq,
613 .force_encap = data->force_encap,
614 .fragmentation = data->fragmentation,
615 .childless = data->childless,
616 .me = strdup(data->local),
617 .my_ranges = linked_list_create(),
618 .my_hosts = linked_list_create(),
619 .other = strdup(data->remote),
620 .other_ranges = linked_list_create(),
621 .other_hosts = linked_list_create(),
622 .my_port = data->local_port,
623 .other_port = data->remote_port,
624 .dscp = data->dscp,
625 .proposals = linked_list_create(),
626 );
627
628 parse_addresses(data->local, this->my_hosts, this->my_ranges);
629 parse_addresses(data->remote, this->other_hosts, this->other_ranges);
630
631 return &this->public;
632 }