Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/tasks/mode_config.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2011 Martin Willi
3: * Copyright (C) 2011 revosec AG
4: *
5: * This program is free software; you can redistribute it and/or modify it
6: * under the terms of the GNU General Public License as published by the
7: * Free Software Foundation; either version 2 of the License, or (at your
8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9: *
10: * This program is distributed in the hope that it will be useful, but
11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13: * for more details.
14: */
15:
16: #include "mode_config.h"
17:
18: #include <daemon.h>
19: #include <encoding/payloads/cp_payload.h>
20:
21: typedef struct private_mode_config_t private_mode_config_t;
22:
23: /**
24: * Private members of a mode_config_t task.
25: */
26: struct private_mode_config_t {
27:
28: /**
29: * Public methods and task_t interface.
30: */
31: mode_config_t public;
32:
33: /**
34: * Assigned IKE_SA.
35: */
36: ike_sa_t *ike_sa;
37:
38: /**
39: * Are we the initiator?
40: */
41: bool initiator;
42:
43: /**
44: * Use pull (CFG_REQUEST/RESPONSE) or push (CFG_SET/ACK)?
45: */
46: bool pull;
47:
48: /**
49: * Received list of virtual IPs, host_t*
50: */
51: linked_list_t *vips;
52:
53: /**
54: * Requested/received list of attributes, entry_t
55: */
56: linked_list_t *attributes;
57:
58: /**
59: * Identifier to include in response
60: */
61: uint16_t identifier;
62: };
63:
64: /**
65: * Entry for a attribute and associated handler
66: */
67: typedef struct {
68: /** attribute type */
69: configuration_attribute_type_t type;
70: /** handler for this attribute */
71: attribute_handler_t *handler;
72: } entry_t;
73:
74: /**
75: * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
76: */
77: static configuration_attribute_t *build_vip(host_t *vip)
78: {
79: configuration_attribute_type_t type = INTERNAL_IP4_ADDRESS;
80: chunk_t chunk;
81:
82: if (vip->get_family(vip) == AF_INET6)
83: {
84: type = INTERNAL_IP6_ADDRESS;
85: }
86: if (vip->is_anyaddr(vip))
87: {
88: chunk = chunk_empty;
89: }
90: else
91: {
92: chunk = vip->get_address(vip);
93: }
94: return configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE,
95: type, chunk);
96: }
97:
98: /**
99: * Handle a received attribute as initiator
100: */
101: static void handle_attribute(private_mode_config_t *this,
102: configuration_attribute_t *ca)
103: {
104: attribute_handler_t *handler = NULL;
105: enumerator_t *enumerator;
106: entry_t *entry;
107:
108: /* find the handler which requested this attribute */
109: enumerator = this->attributes->create_enumerator(this->attributes);
110: while (enumerator->enumerate(enumerator, &entry))
111: {
112: if (entry->type == ca->get_type(ca))
113: {
114: handler = entry->handler;
115: this->attributes->remove_at(this->attributes, enumerator);
116: free(entry);
117: break;
118: }
119: }
120: enumerator->destroy(enumerator);
121:
122: /* and pass it to the handle function */
123: handler = charon->attributes->handle(charon->attributes,
124: this->ike_sa, handler, ca->get_type(ca), ca->get_chunk(ca));
125: this->ike_sa->add_configuration_attribute(this->ike_sa,
126: handler, ca->get_type(ca), ca->get_chunk(ca));
127: }
128:
129: /**
130: * process a single configuration attribute
131: */
132: static void process_attribute(private_mode_config_t *this,
133: configuration_attribute_t *ca)
134: {
135: host_t *ip;
136: chunk_t addr;
137: int family = AF_INET6;
138:
139: switch (ca->get_type(ca))
140: {
141: case INTERNAL_IP4_ADDRESS:
142: family = AF_INET;
143: /* fall */
144: case INTERNAL_IP6_ADDRESS:
145: {
146: addr = ca->get_chunk(ca);
147: if (addr.len == 0)
148: {
149: ip = host_create_any(family);
150: }
151: else
152: {
153: /* skip prefix byte in IPv6 payload sent by older releases */
154: if (family == AF_INET6 && addr.len == 17)
155: {
156: addr.len--;
157: }
158: ip = host_create_from_chunk(family, addr, 0);
159: }
160: if (ip)
161: {
162: this->vips->insert_last(this->vips, ip);
163: }
164: break;
165: }
166: default:
167: {
168: if (this->initiator == this->pull)
169: {
170: handle_attribute(this, ca);
171: }
172: }
173: }
174: }
175:
176: /**
177: * Check if config allows push mode when acting as task responder
178: */
179: static bool accept_push(private_mode_config_t *this)
180: {
181: enumerator_t *enumerator;
182: peer_cfg_t *config;
183: bool vip;
184: host_t *host;
185:
186: config = this->ike_sa->get_peer_cfg(this->ike_sa);
187: enumerator = config->create_virtual_ip_enumerator(config);
188: vip = enumerator->enumerate(enumerator, &host);
189: enumerator->destroy(enumerator);
190:
191: return vip && !config->use_pull_mode(config);
192: }
193:
194: /**
195: * Scan for configuration payloads and attributes
196: */
197: static void process_payloads(private_mode_config_t *this, message_t *message)
198: {
199: enumerator_t *enumerator, *attributes;
200: payload_t *payload;
201:
202: enumerator = message->create_payload_enumerator(message);
203: while (enumerator->enumerate(enumerator, &payload))
204: {
205: if (payload->get_type(payload) == PLV1_CONFIGURATION)
206: {
207: cp_payload_t *cp = (cp_payload_t*)payload;
208: configuration_attribute_t *ca;
209:
210: switch (cp->get_type(cp))
211: {
212: case CFG_SET:
213: /* when acting as a responder, we detect the mode using
214: * the type of configuration payload. But we should double
215: * check the peer is allowed to use push mode on us. */
216: if (!this->initiator && accept_push(this))
217: {
218: this->pull = FALSE;
219: }
220: /* FALL */
221: case CFG_REQUEST:
222: this->identifier = cp->get_identifier(cp);
223: /* FALL */
224: case CFG_REPLY:
225: attributes = cp->create_attribute_enumerator(cp);
226: while (attributes->enumerate(attributes, &ca))
227: {
228: DBG2(DBG_IKE, "processing %N attribute",
229: configuration_attribute_type_names, ca->get_type(ca));
230: process_attribute(this, ca);
231: }
232: attributes->destroy(attributes);
233: break;
234: case CFG_ACK:
235: break;
236: default:
237: DBG1(DBG_IKE, "ignoring %N config payload",
238: config_type_names, cp->get_type(cp));
239: break;
240: }
241: }
242: }
243: enumerator->destroy(enumerator);
244: }
245:
246: /**
247: * Add an attribute to a configuration payload, and store it in task
248: */
249: static void add_attribute(private_mode_config_t *this, cp_payload_t *cp,
250: configuration_attribute_type_t type, chunk_t data,
251: attribute_handler_t *handler)
252: {
253: entry_t *entry;
254:
255: cp->add_attribute(cp,
256: configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE,
257: type, data));
258: INIT(entry,
259: .type = type,
260: .handler = handler,
261: );
262: this->attributes->insert_last(this->attributes, entry);
263: }
264:
265: /**
266: * Build a CFG_REQUEST as initiator
267: */
268: static status_t build_request(private_mode_config_t *this, message_t *message)
269: {
270: cp_payload_t *cp;
271: enumerator_t *enumerator;
272: attribute_handler_t *handler;
273: peer_cfg_t *config;
274: configuration_attribute_type_t type;
275: chunk_t data;
276: linked_list_t *vips;
277: host_t *host;
278:
279: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST);
280:
281: vips = linked_list_create();
282:
283: /* reuse virtual IP if we already have one */
284: enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE);
285: while (enumerator->enumerate(enumerator, &host))
286: {
287: vips->insert_last(vips, host);
288: }
289: enumerator->destroy(enumerator);
290:
291: if (vips->get_count(vips) == 0)
292: {
293: config = this->ike_sa->get_peer_cfg(this->ike_sa);
294: enumerator = config->create_virtual_ip_enumerator(config);
295: while (enumerator->enumerate(enumerator, &host))
296: {
297: vips->insert_last(vips, host);
298: }
299: enumerator->destroy(enumerator);
300: }
301:
302: if (vips->get_count(vips))
303: {
304: enumerator = vips->create_enumerator(vips);
305: while (enumerator->enumerate(enumerator, &host))
306: {
307: cp->add_attribute(cp, build_vip(host));
308: }
309: enumerator->destroy(enumerator);
310: }
311:
312: enumerator = charon->attributes->create_initiator_enumerator(
313: charon->attributes, this->ike_sa, vips);
314: while (enumerator->enumerate(enumerator, &handler, &type, &data))
315: {
316: add_attribute(this, cp, type, data, handler);
317: }
318: enumerator->destroy(enumerator);
319:
320: vips->destroy(vips);
321:
322: message->add_payload(message, (payload_t*)cp);
323:
324: return NEED_MORE;
325: }
326:
327: /**
328: * Build a CFG_SET as initiator
329: */
330: static status_t build_set(private_mode_config_t *this, message_t *message)
331: {
332: enumerator_t *enumerator;
333: configuration_attribute_type_t type;
334: chunk_t value;
335: cp_payload_t *cp;
336: peer_cfg_t *config;
337: identification_t *id;
338: linked_list_t *pools, *migrated, *vips;
339: host_t *any4, *any6, *found;
340: char *name;
341:
342: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_SET);
343:
344: id = this->ike_sa->get_other_eap_id(this->ike_sa);
345: config = this->ike_sa->get_peer_cfg(this->ike_sa);
346:
347: /* if we migrated virtual IPs during reauthentication, reassign them */
348: migrated = linked_list_create_from_enumerator(
349: this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
350: FALSE));
351: vips = migrated->clone_offset(migrated, offsetof(host_t, clone));
352: migrated->destroy(migrated);
353: this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
354:
355: /* in push mode, we ask each configured pool for an address */
356: if (!vips->get_count(vips))
357: {
358: any4 = host_create_any(AF_INET);
359: any6 = host_create_any(AF_INET6);
360: enumerator = config->create_pool_enumerator(config);
361: while (enumerator->enumerate(enumerator, &name))
362: {
363: pools = linked_list_create_with_items(name, NULL);
364: /* try IPv4, then IPv6 */
365: found = charon->attributes->acquire_address(charon->attributes,
366: pools, this->ike_sa, any4);
367: if (!found)
368: {
369: found = charon->attributes->acquire_address(charon->attributes,
370: pools, this->ike_sa, any6);
371: }
372: pools->destroy(pools);
373: if (found)
374: {
375: vips->insert_last(vips, found);
376: }
377: }
378: enumerator->destroy(enumerator);
379: any4->destroy(any4);
380: any6->destroy(any6);
381: }
382:
383: enumerator = vips->create_enumerator(vips);
384: while (enumerator->enumerate(enumerator, &found))
385: {
386: DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
387: this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
388: cp->add_attribute(cp, build_vip(found));
389: this->vips->insert_last(this->vips, found);
390: vips->remove_at(vips, enumerator);
391: }
392: enumerator->destroy(enumerator);
393: vips->destroy(vips);
394:
395: charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
396:
397: /* query registered providers for additional attributes to include */
398: pools = linked_list_create_from_enumerator(
399: config->create_pool_enumerator(config));
400: enumerator = charon->attributes->create_responder_enumerator(
401: charon->attributes, pools, this->ike_sa, this->vips);
402: while (enumerator->enumerate(enumerator, &type, &value))
403: {
404: add_attribute(this, cp, type, value, NULL);
405: }
406: enumerator->destroy(enumerator);
407: pools->destroy(pools);
408:
409: message->add_payload(message, (payload_t*)cp);
410:
411: return SUCCESS;
412: }
413:
414: METHOD(task_t, build_i, status_t,
415: private_mode_config_t *this, message_t *message)
416: {
417: if (this->pull)
418: {
419: return build_request(this, message);
420: }
421: return build_set(this, message);
422: }
423:
424: /**
425: * Store received virtual IPs to the IKE_SA, install them
426: */
427: static void install_vips(private_mode_config_t *this)
428: {
429: enumerator_t *enumerator;
430: host_t *host;
431:
432: this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE);
433:
434: enumerator = this->vips->create_enumerator(this->vips);
435: while (enumerator->enumerate(enumerator, &host))
436: {
437: if (!host->is_anyaddr(host))
438: {
439: this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
440: }
441: }
442: enumerator->destroy(enumerator);
443:
444: charon->bus->handle_vips(charon->bus, this->ike_sa, TRUE);
445: }
446:
447: METHOD(task_t, process_r, status_t,
448: private_mode_config_t *this, message_t *message)
449: {
450: process_payloads(this, message);
451:
452: if (!this->pull)
453: {
454: install_vips(this);
455: }
456: return NEED_MORE;
457: }
458:
459: /**
460: * Assign a migrated virtual IP
461: */
462: static host_t *assign_migrated_vip(linked_list_t *migrated, host_t *requested)
463: {
464: enumerator_t *enumerator;
465: host_t *found = NULL, *vip;
466:
467: enumerator = migrated->create_enumerator(migrated);
468: while (enumerator->enumerate(enumerator, &vip))
469: {
470: if (vip->ip_equals(vip, requested) ||
471: (requested->is_anyaddr(requested) &&
472: requested->get_family(requested) == vip->get_family(vip)))
473: {
474: migrated->remove_at(migrated, enumerator);
475: found = vip;
476: break;
477: }
478: }
479: enumerator->destroy(enumerator);
480: return found;
481: }
482:
483: /**
484: * Build CFG_REPLY message after receiving CFG_REQUEST
485: */
486: static status_t build_reply(private_mode_config_t *this, message_t *message)
487: {
488: enumerator_t *enumerator;
489: configuration_attribute_type_t type;
490: chunk_t value;
491: cp_payload_t *cp;
492: peer_cfg_t *config;
493: identification_t *id;
494: linked_list_t *vips, *pools, *migrated;
495: host_t *requested, *found;
496:
497: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY);
498:
499: id = this->ike_sa->get_other_eap_id(this->ike_sa);
500: config = this->ike_sa->get_peer_cfg(this->ike_sa);
501: pools = linked_list_create_from_enumerator(
502: config->create_pool_enumerator(config));
503: /* if we migrated virtual IPs during reauthentication, reassign them */
504: vips = linked_list_create_from_enumerator(
505: this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
506: FALSE));
507: migrated = vips->clone_offset(vips, offsetof(host_t, clone));
508: vips->destroy(vips);
509: this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
510:
511: vips = linked_list_create();
512: enumerator = this->vips->create_enumerator(this->vips);
513: while (enumerator->enumerate(enumerator, &requested))
514: {
515: DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
516:
517: found = assign_migrated_vip(migrated, requested);
518: if (!found)
519: {
520: found = charon->attributes->acquire_address(charon->attributes,
521: pools, this->ike_sa, requested);
522: }
523: if (found)
524: {
525: DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
526: this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
527: cp->add_attribute(cp, build_vip(found));
528: vips->insert_last(vips, found);
529: }
530: else
531: {
532: DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
533: requested, id);
534: }
535: }
536: enumerator->destroy(enumerator);
537:
538: charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
539:
540: /* query registered providers for additional attributes to include */
541: enumerator = charon->attributes->create_responder_enumerator(
542: charon->attributes, pools, this->ike_sa, vips);
543: while (enumerator->enumerate(enumerator, &type, &value))
544: {
545: cp->add_attribute(cp,
546: configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE,
547: type, value));
548: }
549: enumerator->destroy(enumerator);
550: /* if a client did not re-request all addresses, release them */
551: enumerator = migrated->create_enumerator(migrated);
552: while (enumerator->enumerate(enumerator, &found))
553: {
554: charon->attributes->release_address(charon->attributes,
555: pools, found, this->ike_sa);
556: }
557: enumerator->destroy(enumerator);
558: migrated->destroy_offset(migrated, offsetof(host_t, destroy));
559: vips->destroy_offset(vips, offsetof(host_t, destroy));
560: pools->destroy(pools);
561:
562: cp->set_identifier(cp, this->identifier);
563: message->add_payload(message, (payload_t*)cp);
564:
565: return SUCCESS;
566: }
567:
568: /**
569: * Build CFG_ACK for a received CFG_SET
570: */
571: static status_t build_ack(private_mode_config_t *this, message_t *message)
572: {
573: cp_payload_t *cp;
574: enumerator_t *enumerator;
575: host_t *host;
576: configuration_attribute_type_t type;
577: entry_t *entry;
578:
579: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_ACK);
580:
581: /* return empty attributes for installed IPs */
582:
583: enumerator = this->vips->create_enumerator(this->vips);
584: while (enumerator->enumerate(enumerator, &host))
585: {
586: if (host->get_family(host) == AF_INET6)
587: {
588: type = INTERNAL_IP6_ADDRESS;
589: }
590: else
591: {
592: type = INTERNAL_IP4_ADDRESS;
593: }
594: cp->add_attribute(cp, configuration_attribute_create_chunk(
595: PLV1_CONFIGURATION_ATTRIBUTE, type, chunk_empty));
596: }
597: enumerator->destroy(enumerator);
598:
599: enumerator = this->attributes->create_enumerator(this->attributes);
600: while (enumerator->enumerate(enumerator, &entry))
601: {
602: cp->add_attribute(cp,
603: configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE,
604: entry->type, chunk_empty));
605: }
606: enumerator->destroy(enumerator);
607:
608: cp->set_identifier(cp, this->identifier);
609: message->add_payload(message, (payload_t*)cp);
610:
611: return SUCCESS;
612: }
613:
614: METHOD(task_t, build_r, status_t,
615: private_mode_config_t *this, message_t *message)
616: {
617: if (this->pull)
618: {
619: return build_reply(this, message);
620: }
621: return build_ack(this, message);
622: }
623:
624: METHOD(task_t, process_i, status_t,
625: private_mode_config_t *this, message_t *message)
626: {
627: process_payloads(this, message);
628:
629: if (this->pull)
630: {
631: install_vips(this);
632: }
633: return SUCCESS;
634: }
635:
636: METHOD(task_t, get_type, task_type_t,
637: private_mode_config_t *this)
638: {
639: return TASK_MODE_CONFIG;
640: }
641:
642: METHOD(task_t, migrate, void,
643: private_mode_config_t *this, ike_sa_t *ike_sa)
644: {
645: this->ike_sa = ike_sa;
646: this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
647: this->vips = linked_list_create();
648: this->attributes->destroy_function(this->attributes, free);
649: this->attributes = linked_list_create();
650: }
651:
652: METHOD(task_t, destroy, void,
653: private_mode_config_t *this)
654: {
655: this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
656: this->attributes->destroy_function(this->attributes, free);
657: free(this);
658: }
659:
660: /*
661: * Described in header.
662: */
663: mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator, bool pull)
664: {
665: private_mode_config_t *this;
666:
667: INIT(this,
668: .public = {
669: .task = {
670: .get_type = _get_type,
671: .migrate = _migrate,
672: .destroy = _destroy,
673: },
674: },
675: .initiator = initiator,
676: .pull = initiator ? pull : TRUE,
677: .ike_sa = ike_sa,
678: .attributes = linked_list_create(),
679: .vips = linked_list_create(),
680: );
681:
682: if (initiator)
683: {
684: this->public.task.build = _build_i;
685: this->public.task.process = _process_i;
686: }
687: else
688: {
689: this->public.task.build = _build_r;
690: this->public.task.process = _process_r;
691: }
692:
693: return &this->public;
694: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>