Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/tasks/ike_config.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2007 Martin Willi
! 3: * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 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>.
! 10: *
! 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
! 14: * for more details.
! 15: */
! 16:
! 17: #include "ike_config.h"
! 18:
! 19: #include <daemon.h>
! 20: #include <encoding/payloads/cp_payload.h>
! 21:
! 22: typedef struct private_ike_config_t private_ike_config_t;
! 23:
! 24: /**
! 25: * Private members of a ike_config_t task.
! 26: */
! 27: struct private_ike_config_t {
! 28:
! 29: /**
! 30: * Public methods and task_t interface.
! 31: */
! 32: ike_config_t public;
! 33:
! 34: /**
! 35: * Assigned IKE_SA.
! 36: */
! 37: ike_sa_t *ike_sa;
! 38:
! 39: /**
! 40: * Are we the initiator?
! 41: */
! 42: bool initiator;
! 43:
! 44: /**
! 45: * Did we request a virtual IP?
! 46: */
! 47: bool vip_requested;
! 48:
! 49: /**
! 50: * Received list of virtual IPs, host_t*
! 51: */
! 52: linked_list_t *vips;
! 53:
! 54: /**
! 55: * list of attributes requested and its handler, entry_t
! 56: */
! 57: linked_list_t *requested;
! 58: };
! 59:
! 60: /**
! 61: * Entry for a requested attribute and the requesting handler
! 62: */
! 63: typedef struct {
! 64: /** attribute requested */
! 65: configuration_attribute_type_t type;
! 66: /** handler requesting this attribute */
! 67: attribute_handler_t *handler;
! 68: } entry_t;
! 69:
! 70: /**
! 71: * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
! 72: */
! 73: static configuration_attribute_t *build_vip(host_t *vip)
! 74: {
! 75: configuration_attribute_type_t type;
! 76: chunk_t chunk, prefix;
! 77:
! 78: if (vip->get_family(vip) == AF_INET)
! 79: {
! 80: type = INTERNAL_IP4_ADDRESS;
! 81: if (vip->is_anyaddr(vip))
! 82: {
! 83: chunk = chunk_empty;
! 84: }
! 85: else
! 86: {
! 87: chunk = vip->get_address(vip);
! 88: }
! 89: }
! 90: else
! 91: {
! 92: type = INTERNAL_IP6_ADDRESS;
! 93: if (vip->is_anyaddr(vip))
! 94: {
! 95: chunk = chunk_empty;
! 96: }
! 97: else
! 98: {
! 99: prefix = chunk_alloca(1);
! 100: *prefix.ptr = 64;
! 101: chunk = vip->get_address(vip);
! 102: chunk = chunk_cata("cc", chunk, prefix);
! 103: }
! 104: }
! 105: return configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
! 106: type, chunk);
! 107: }
! 108:
! 109: /**
! 110: * Handle a received attribute as initiator
! 111: */
! 112: static void handle_attribute(private_ike_config_t *this,
! 113: configuration_attribute_t *ca)
! 114: {
! 115: attribute_handler_t *handler = NULL;
! 116: enumerator_t *enumerator;
! 117: entry_t *entry;
! 118:
! 119: /* find the handler which requested this attribute */
! 120: enumerator = this->requested->create_enumerator(this->requested);
! 121: while (enumerator->enumerate(enumerator, &entry))
! 122: {
! 123: if (entry->type == ca->get_type(ca))
! 124: {
! 125: handler = entry->handler;
! 126: this->requested->remove_at(this->requested, enumerator);
! 127: free(entry);
! 128: break;
! 129: }
! 130: }
! 131: enumerator->destroy(enumerator);
! 132:
! 133: /* and pass it to the handle function */
! 134: handler = charon->attributes->handle(charon->attributes,
! 135: this->ike_sa, handler, ca->get_type(ca), ca->get_chunk(ca));
! 136: this->ike_sa->add_configuration_attribute(this->ike_sa,
! 137: handler, ca->get_type(ca), ca->get_chunk(ca));
! 138: }
! 139:
! 140: /**
! 141: * process a single configuration attribute
! 142: */
! 143: static void process_attribute(private_ike_config_t *this,
! 144: configuration_attribute_t *ca)
! 145: {
! 146: host_t *ip;
! 147: chunk_t addr;
! 148: int family = AF_INET6;
! 149:
! 150: switch (ca->get_type(ca))
! 151: {
! 152: case INTERNAL_IP4_ADDRESS:
! 153: family = AF_INET;
! 154: /* fall */
! 155: case INTERNAL_IP6_ADDRESS:
! 156: {
! 157: if (this->initiator && !this->vip_requested)
! 158: {
! 159: handle_attribute(this, ca);
! 160: return;
! 161: }
! 162:
! 163: addr = ca->get_chunk(ca);
! 164: if (addr.len == 0)
! 165: {
! 166: ip = host_create_any(family);
! 167: }
! 168: else
! 169: {
! 170: /* skip prefix byte in IPv6 payload*/
! 171: if (family == AF_INET6)
! 172: {
! 173: addr.len--;
! 174: }
! 175: ip = host_create_from_chunk(family, addr, 0);
! 176: }
! 177: if (ip)
! 178: {
! 179: this->vips->insert_last(this->vips, ip);
! 180: }
! 181: break;
! 182: }
! 183: case INTERNAL_IP4_SERVER:
! 184: case INTERNAL_IP6_SERVER:
! 185: /* assume it's a Windows client if we see proprietary attributes */
! 186: this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS);
! 187: /* fall */
! 188: default:
! 189: {
! 190: if (this->initiator)
! 191: {
! 192: handle_attribute(this, ca);
! 193: }
! 194: }
! 195: }
! 196: }
! 197:
! 198: /**
! 199: * Scan for configuration payloads and attributes
! 200: */
! 201: static void process_payloads(private_ike_config_t *this, message_t *message)
! 202: {
! 203: enumerator_t *enumerator, *attributes;
! 204: payload_t *payload;
! 205:
! 206: enumerator = message->create_payload_enumerator(message);
! 207: while (enumerator->enumerate(enumerator, &payload))
! 208: {
! 209: if (payload->get_type(payload) == PLV2_CONFIGURATION)
! 210: {
! 211: cp_payload_t *cp = (cp_payload_t*)payload;
! 212: configuration_attribute_t *ca;
! 213:
! 214: switch (cp->get_type(cp))
! 215: {
! 216: case CFG_REQUEST:
! 217: case CFG_REPLY:
! 218: {
! 219: attributes = cp->create_attribute_enumerator(cp);
! 220: while (attributes->enumerate(attributes, &ca))
! 221: {
! 222: DBG2(DBG_IKE, "processing %N attribute",
! 223: configuration_attribute_type_names, ca->get_type(ca));
! 224: process_attribute(this, ca);
! 225: }
! 226: attributes->destroy(attributes);
! 227: break;
! 228: }
! 229: default:
! 230: DBG1(DBG_IKE, "ignoring %N config payload",
! 231: config_type_names, cp->get_type(cp));
! 232: break;
! 233: }
! 234: }
! 235: }
! 236: enumerator->destroy(enumerator);
! 237: }
! 238:
! 239: METHOD(task_t, build_i, status_t,
! 240: private_ike_config_t *this, message_t *message)
! 241: {
! 242: if (message->get_message_id(message) == 1)
! 243: { /* in first IKE_AUTH only */
! 244: cp_payload_t *cp = NULL;
! 245: enumerator_t *enumerator;
! 246: attribute_handler_t *handler;
! 247: peer_cfg_t *config;
! 248: configuration_attribute_type_t type;
! 249: chunk_t data;
! 250: linked_list_t *vips;
! 251: host_t *host;
! 252:
! 253: vips = linked_list_create();
! 254:
! 255: /* reuse virtual IP if we already have one */
! 256: enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
! 257: TRUE);
! 258: while (enumerator->enumerate(enumerator, &host))
! 259: {
! 260: vips->insert_last(vips, host);
! 261: }
! 262: enumerator->destroy(enumerator);
! 263:
! 264: if (vips->get_count(vips) == 0)
! 265: {
! 266: config = this->ike_sa->get_peer_cfg(this->ike_sa);
! 267: enumerator = config->create_virtual_ip_enumerator(config);
! 268: while (enumerator->enumerate(enumerator, &host))
! 269: {
! 270: vips->insert_last(vips, host);
! 271: }
! 272: enumerator->destroy(enumerator);
! 273: }
! 274:
! 275: if (vips->get_count(vips))
! 276: {
! 277: cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REQUEST);
! 278: enumerator = vips->create_enumerator(vips);
! 279: while (enumerator->enumerate(enumerator, &host))
! 280: {
! 281: cp->add_attribute(cp, build_vip(host));
! 282: }
! 283: enumerator->destroy(enumerator);
! 284: this->vip_requested = TRUE;
! 285: }
! 286:
! 287: enumerator = charon->attributes->create_initiator_enumerator(
! 288: charon->attributes, this->ike_sa, vips);
! 289: while (enumerator->enumerate(enumerator, &handler, &type, &data))
! 290: {
! 291: configuration_attribute_t *ca;
! 292: entry_t *entry;
! 293:
! 294: /* create configuration attribute */
! 295: DBG2(DBG_IKE, "building %N attribute",
! 296: configuration_attribute_type_names, type);
! 297: ca = configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
! 298: type, data);
! 299: if (!cp)
! 300: {
! 301: cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REQUEST);
! 302: }
! 303: cp->add_attribute(cp, ca);
! 304:
! 305: /* save handler along with requested type */
! 306: entry = malloc_thing(entry_t);
! 307: entry->type = type;
! 308: entry->handler = handler;
! 309:
! 310: this->requested->insert_last(this->requested, entry);
! 311: }
! 312: enumerator->destroy(enumerator);
! 313:
! 314: vips->destroy(vips);
! 315:
! 316: if (cp)
! 317: {
! 318: message->add_payload(message, (payload_t*)cp);
! 319: }
! 320: else
! 321: { /* we don't expect a CFG_REPLY */
! 322: return SUCCESS;
! 323: }
! 324: }
! 325: return NEED_MORE;
! 326: }
! 327:
! 328: METHOD(task_t, process_r, status_t,
! 329: private_ike_config_t *this, message_t *message)
! 330: {
! 331: if (message->get_message_id(message) == 1)
! 332: { /* in first IKE_AUTH only */
! 333: process_payloads(this, message);
! 334: }
! 335: return NEED_MORE;
! 336: }
! 337:
! 338: METHOD(task_t, build_r, status_t,
! 339: private_ike_config_t *this, message_t *message)
! 340: {
! 341: if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
! 342: { /* in last IKE_AUTH exchange */
! 343: enumerator_t *enumerator;
! 344: configuration_attribute_type_t type;
! 345: chunk_t value;
! 346: cp_payload_t *cp = NULL;
! 347: peer_cfg_t *config;
! 348: identification_t *id;
! 349: linked_list_t *vips, *pools;
! 350: host_t *requested;
! 351:
! 352: if (this->ike_sa->has_condition(this->ike_sa, COND_REDIRECTED))
! 353: { /* don't assign attributes for redirected SAs */
! 354: return SUCCESS;
! 355: }
! 356:
! 357: id = this->ike_sa->get_other_eap_id(this->ike_sa);
! 358: config = this->ike_sa->get_peer_cfg(this->ike_sa);
! 359: vips = linked_list_create();
! 360: pools = linked_list_create_from_enumerator(
! 361: config->create_pool_enumerator(config));
! 362:
! 363: this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
! 364:
! 365: enumerator = this->vips->create_enumerator(this->vips);
! 366: while (enumerator->enumerate(enumerator, &requested))
! 367: {
! 368: host_t *found = NULL;
! 369:
! 370: /* query all pools until we get an address */
! 371: DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
! 372:
! 373: found = charon->attributes->acquire_address(charon->attributes,
! 374: pools, this->ike_sa, requested);
! 375: if (found)
! 376: {
! 377: DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
! 378: this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
! 379: if (!cp)
! 380: {
! 381: cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REPLY);
! 382: }
! 383: cp->add_attribute(cp, build_vip(found));
! 384: vips->insert_last(vips, found);
! 385: }
! 386: else
! 387: {
! 388: DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
! 389: requested, id);
! 390: }
! 391: }
! 392: enumerator->destroy(enumerator);
! 393:
! 394: if (this->vips->get_count(this->vips) && !vips->get_count(vips))
! 395: {
! 396: DBG1(DBG_IKE, "no virtual IP found, sending %N",
! 397: notify_type_names, INTERNAL_ADDRESS_FAILURE);
! 398: charon->bus->alert(charon->bus, ALERT_VIP_FAILURE, this->vips);
! 399: message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
! 400: chunk_empty);
! 401: vips->destroy_offset(vips, offsetof(host_t, destroy));
! 402: pools->destroy(pools);
! 403: return SUCCESS;
! 404: }
! 405: charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
! 406:
! 407: if (pools->get_count(pools) && !this->vips->get_count(this->vips))
! 408: {
! 409: DBG1(DBG_IKE, "expected a virtual IP request, sending %N",
! 410: notify_type_names, FAILED_CP_REQUIRED);
! 411: charon->bus->alert(charon->bus, ALERT_VIP_FAILURE, this->vips);
! 412: message->add_notify(message, FALSE, FAILED_CP_REQUIRED, chunk_empty);
! 413: vips->destroy_offset(vips, offsetof(host_t, destroy));
! 414: pools->destroy(pools);
! 415: return SUCCESS;
! 416: }
! 417:
! 418: /* query registered providers for additional attributes to include */
! 419: enumerator = charon->attributes->create_responder_enumerator(
! 420: charon->attributes, pools, this->ike_sa, vips);
! 421: while (enumerator->enumerate(enumerator, &type, &value))
! 422: {
! 423: if (!cp)
! 424: {
! 425: cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REPLY);
! 426: }
! 427: DBG2(DBG_IKE, "building %N attribute",
! 428: configuration_attribute_type_names, type);
! 429: cp->add_attribute(cp,
! 430: configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
! 431: type, value));
! 432: }
! 433: enumerator->destroy(enumerator);
! 434: vips->destroy_offset(vips, offsetof(host_t, destroy));
! 435: pools->destroy(pools);
! 436:
! 437: if (cp)
! 438: {
! 439: message->add_payload(message, (payload_t*)cp);
! 440: }
! 441: return SUCCESS;
! 442: }
! 443: return NEED_MORE;
! 444: }
! 445:
! 446: METHOD(task_t, process_i, status_t,
! 447: private_ike_config_t *this, message_t *message)
! 448: {
! 449: if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
! 450: { /* in last IKE_AUTH exchange */
! 451: enumerator_t *enumerator;
! 452: host_t *host;
! 453:
! 454: process_payloads(this, message);
! 455:
! 456: this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE);
! 457:
! 458: enumerator = this->vips->create_enumerator(this->vips);
! 459: while (enumerator->enumerate(enumerator, &host))
! 460: {
! 461: if (!host->is_anyaddr(host))
! 462: {
! 463: this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
! 464: }
! 465: }
! 466: enumerator->destroy(enumerator);
! 467:
! 468: charon->bus->handle_vips(charon->bus, this->ike_sa, TRUE);
! 469: return SUCCESS;
! 470: }
! 471: return NEED_MORE;
! 472: }
! 473:
! 474: METHOD(task_t, get_type, task_type_t,
! 475: private_ike_config_t *this)
! 476: {
! 477: return TASK_IKE_CONFIG;
! 478: }
! 479:
! 480: METHOD(task_t, migrate, void,
! 481: private_ike_config_t *this, ike_sa_t *ike_sa)
! 482: {
! 483: this->ike_sa = ike_sa;
! 484: this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
! 485: this->vips = linked_list_create();
! 486: this->requested->destroy_function(this->requested, free);
! 487: this->requested = linked_list_create();
! 488: }
! 489:
! 490: METHOD(task_t, destroy, void,
! 491: private_ike_config_t *this)
! 492: {
! 493: this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
! 494: this->requested->destroy_function(this->requested, free);
! 495: free(this);
! 496: }
! 497:
! 498: /*
! 499: * Described in header.
! 500: */
! 501: ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
! 502: {
! 503: private_ike_config_t *this;
! 504:
! 505: INIT(this,
! 506: .public = {
! 507: .task = {
! 508: .get_type = _get_type,
! 509: .migrate = _migrate,
! 510: .destroy = _destroy,
! 511: },
! 512: },
! 513: .initiator = initiator,
! 514: .ike_sa = ike_sa,
! 515: .vips = linked_list_create(),
! 516: .requested = linked_list_create(),
! 517: );
! 518:
! 519: if (initiator)
! 520: {
! 521: this->public.task.build = _build_i;
! 522: this->public.task.process = _process_i;
! 523: }
! 524: else
! 525: {
! 526: this->public.task.build = _build_r;
! 527: this->public.task.process = _process_r;
! 528: }
! 529:
! 530: return &this->public;
! 531: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>