Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/tasks/isakmp_natd.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2006-2011 Tobias Brunner,
! 3: * Copyright (C) 2006-2007 Martin Willi
! 4: * Copyright (C) 2006 Daniel Roethlisberger
! 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: /*
! 19: * Copyright (C) 2012 Volker RĂ¼melin
! 20: *
! 21: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 22: * of this software and associated documentation files (the "Software"), to deal
! 23: * in the Software without restriction, including without limitation the rights
! 24: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 25: * copies of the Software, and to permit persons to whom the Software is
! 26: * furnished to do so, subject to the following conditions:
! 27: *
! 28: * The above copyright notice and this permission notice shall be included in
! 29: * all copies or substantial portions of the Software.
! 30: *
! 31: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 32: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 33: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 34: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 35: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 36: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 37: * THE SOFTWARE.
! 38: */
! 39:
! 40: #include "isakmp_natd.h"
! 41:
! 42: #include <string.h>
! 43:
! 44: #include <daemon.h>
! 45: #include <sa/ikev1/keymat_v1.h>
! 46: #include <config/peer_cfg.h>
! 47: #include <crypto/hashers/hasher.h>
! 48: #include <encoding/payloads/hash_payload.h>
! 49:
! 50: typedef struct private_isakmp_natd_t private_isakmp_natd_t;
! 51:
! 52: /**
! 53: * Private members of a ike_natt_t task.
! 54: */
! 55: struct private_isakmp_natd_t {
! 56:
! 57: /**
! 58: * Public interface.
! 59: */
! 60: isakmp_natd_t public;
! 61:
! 62: /**
! 63: * Assigned IKE_SA.
! 64: */
! 65: ike_sa_t *ike_sa;
! 66:
! 67: /**
! 68: * Are we the initiator?
! 69: */
! 70: bool initiator;
! 71:
! 72: /**
! 73: * Keymat derivation (from SA)
! 74: */
! 75: keymat_v1_t *keymat;
! 76:
! 77: /**
! 78: * Did we process any NAT detection payloads for a source address?
! 79: */
! 80: bool src_seen;
! 81:
! 82: /**
! 83: * Did we process any NAT detection payloads for a destination address?
! 84: */
! 85: bool dst_seen;
! 86:
! 87: /**
! 88: * Have we found a matching source address NAT hash?
! 89: */
! 90: bool src_matched;
! 91:
! 92: /**
! 93: * Have we found a matching destination address NAT hash?
! 94: */
! 95: bool dst_matched;
! 96: };
! 97:
! 98: /**
! 99: * Check if UDP encapsulation has to be forced either by config or required
! 100: * by the kernel interface
! 101: */
! 102: static bool force_encap(ike_cfg_t *ike_cfg)
! 103: {
! 104: if (!ike_cfg->force_encap(ike_cfg))
! 105: {
! 106: return charon->kernel->get_features(charon->kernel) &
! 107: KERNEL_REQUIRE_UDP_ENCAPSULATION;
! 108: }
! 109: return TRUE;
! 110: }
! 111:
! 112: /**
! 113: * Get NAT-D payload type (RFC 3947 or RFC 3947 drafts).
! 114: */
! 115: static payload_type_t get_nat_d_payload_type(ike_sa_t *ike_sa)
! 116: {
! 117: if (ike_sa->supports_extension(ike_sa, EXT_NATT_DRAFT_02_03))
! 118: {
! 119: return PLV1_NAT_D_DRAFT_00_03;
! 120: }
! 121: return PLV1_NAT_D;
! 122: }
! 123:
! 124: /**
! 125: * Build NAT detection hash for a host.
! 126: */
! 127: static chunk_t generate_natd_hash(private_isakmp_natd_t *this,
! 128: ike_sa_id_t *ike_sa_id, host_t *host)
! 129: {
! 130: hasher_t *hasher;
! 131: chunk_t natd_chunk, natd_hash;
! 132: uint64_t spi_i, spi_r;
! 133: uint16_t port;
! 134:
! 135: hasher = this->keymat->get_hasher(this->keymat);
! 136: if (!hasher)
! 137: {
! 138: DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
! 139: return chunk_empty;
! 140: }
! 141:
! 142: spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
! 143: spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
! 144: port = htons(host->get_port(host));
! 145:
! 146: /* natd_hash = HASH(CKY-I | CKY-R | IP | Port) */
! 147: natd_chunk = chunk_cata("cccc", chunk_from_thing(spi_i),
! 148: chunk_from_thing(spi_r), host->get_address(host),
! 149: chunk_from_thing(port));
! 150: if (!hasher->allocate_hash(hasher, natd_chunk, &natd_hash))
! 151: {
! 152: DBG1(DBG_IKE, "creating NAT-D payload hash failed");
! 153: return chunk_empty;
! 154: }
! 155: DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
! 156: DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
! 157:
! 158: return natd_hash;
! 159: }
! 160:
! 161: /**
! 162: * Build a faked NAT-D payload to enforce UDP encapsulation.
! 163: */
! 164: static chunk_t generate_natd_hash_faked(private_isakmp_natd_t *this)
! 165: {
! 166: hasher_t *hasher;
! 167: chunk_t chunk;
! 168: rng_t *rng;
! 169:
! 170: hasher = this->keymat->get_hasher(this->keymat);
! 171: if (!hasher)
! 172: {
! 173: DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
! 174: return chunk_empty;
! 175: }
! 176: rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
! 177: if (!rng ||
! 178: !rng->allocate_bytes(rng, hasher->get_hash_size(hasher), &chunk))
! 179: {
! 180: DBG1(DBG_IKE, "unable to get random bytes for NAT-D fake");
! 181: DESTROY_IF(rng);
! 182: return chunk_empty;
! 183: }
! 184: rng->destroy(rng);
! 185: return chunk;
! 186: }
! 187:
! 188: /**
! 189: * Build a NAT-D payload.
! 190: */
! 191: static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src,
! 192: host_t *host)
! 193: {
! 194: hash_payload_t *payload;
! 195: ike_cfg_t *config;
! 196: chunk_t hash;
! 197:
! 198: config = this->ike_sa->get_ike_cfg(this->ike_sa);
! 199: if (src && force_encap(config))
! 200: {
! 201: hash = generate_natd_hash_faked(this);
! 202: }
! 203: else
! 204: {
! 205: ike_sa_id_t *ike_sa_id = this->ike_sa->get_id(this->ike_sa);
! 206: hash = generate_natd_hash(this, ike_sa_id, host);
! 207: }
! 208: if (!hash.len)
! 209: {
! 210: return NULL;
! 211: }
! 212: payload = hash_payload_create(get_nat_d_payload_type(this->ike_sa));
! 213: payload->set_hash(payload, hash);
! 214: chunk_free(&hash);
! 215: return payload;
! 216: }
! 217:
! 218: /**
! 219: * Add NAT-D payloads to the message.
! 220: */
! 221: static void add_natd_payloads(private_isakmp_natd_t *this, message_t *message)
! 222: {
! 223: hash_payload_t *payload;
! 224: host_t *host;
! 225:
! 226: /* destination has to be added first */
! 227: host = message->get_destination(message);
! 228: payload = build_natd_payload(this, FALSE, host);
! 229: if (payload)
! 230: {
! 231: message->add_payload(message, (payload_t*)payload);
! 232: }
! 233:
! 234: /* source is added second, compared with IKEv2 we always know the source,
! 235: * as these payloads are added in the second Phase 1 exchange or the
! 236: * response to the first */
! 237: host = message->get_source(message);
! 238: payload = build_natd_payload(this, TRUE, host);
! 239: if (payload)
! 240: {
! 241: message->add_payload(message, (payload_t*)payload);
! 242: }
! 243: }
! 244:
! 245: /**
! 246: * Read NAT-D payloads from message and evaluate them.
! 247: */
! 248: static void process_payloads(private_isakmp_natd_t *this, message_t *message)
! 249: {
! 250: enumerator_t *enumerator;
! 251: payload_t *payload;
! 252: hash_payload_t *hash_payload;
! 253: chunk_t hash, src_hash, dst_hash;
! 254: ike_sa_id_t *ike_sa_id;
! 255: host_t *me, *other;
! 256: ike_cfg_t *config;
! 257:
! 258: /* precompute hashes for incoming NAT-D comparison */
! 259: ike_sa_id = message->get_ike_sa_id(message);
! 260: me = message->get_destination(message);
! 261: other = message->get_source(message);
! 262: dst_hash = generate_natd_hash(this, ike_sa_id, me);
! 263: src_hash = generate_natd_hash(this, ike_sa_id, other);
! 264:
! 265: DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash);
! 266: DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
! 267:
! 268: enumerator = message->create_payload_enumerator(message);
! 269: while (enumerator->enumerate(enumerator, &payload))
! 270: {
! 271: if (payload->get_type(payload) != PLV1_NAT_D &&
! 272: payload->get_type(payload) != PLV1_NAT_D_DRAFT_00_03)
! 273: {
! 274: continue;
! 275: }
! 276: hash_payload = (hash_payload_t*)payload;
! 277: if (!this->dst_seen)
! 278: { /* the first NAT-D payload contains the destination hash */
! 279: this->dst_seen = TRUE;
! 280: hash = hash_payload->get_hash(hash_payload);
! 281: DBG3(DBG_IKE, "received dst_hash %B", &hash);
! 282: if (chunk_equals(hash, dst_hash))
! 283: {
! 284: this->dst_matched = TRUE;
! 285: }
! 286: continue;
! 287: }
! 288: /* the other NAT-D payloads contain source hashes */
! 289: this->src_seen = TRUE;
! 290: if (!this->src_matched)
! 291: {
! 292: hash = hash_payload->get_hash(hash_payload);
! 293: DBG3(DBG_IKE, "received src_hash %B", &hash);
! 294: if (chunk_equals(hash, src_hash))
! 295: {
! 296: this->src_matched = TRUE;
! 297: }
! 298: }
! 299: }
! 300: enumerator->destroy(enumerator);
! 301:
! 302: chunk_free(&src_hash);
! 303: chunk_free(&dst_hash);
! 304:
! 305: if (this->src_seen && this->dst_seen)
! 306: {
! 307: this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
! 308: !this->dst_matched);
! 309: this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
! 310: !this->src_matched);
! 311: config = this->ike_sa->get_ike_cfg(this->ike_sa);
! 312: if (this->dst_matched && this->src_matched &&
! 313: force_encap(config))
! 314: {
! 315: this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
! 316: }
! 317: }
! 318: }
! 319:
! 320: METHOD(task_t, build_i, status_t,
! 321: private_isakmp_natd_t *this, message_t *message)
! 322: {
! 323: status_t result = NEED_MORE;
! 324:
! 325: switch (message->get_exchange_type(message))
! 326: {
! 327: case AGGRESSIVE:
! 328: { /* add NAT-D payloads to the second request, already processed
! 329: * those by the responder contained in the first response */
! 330: result = SUCCESS;
! 331: /* fall */
! 332: }
! 333: case ID_PROT:
! 334: { /* add NAT-D payloads to the second request, need to process
! 335: * those by the responder contained in the second response */
! 336: if (message->get_payload(message, PLV1_SECURITY_ASSOCIATION))
! 337: { /* wait for the second exchange */
! 338: return NEED_MORE;
! 339: }
! 340: add_natd_payloads(this, message);
! 341: return result;
! 342: }
! 343: default:
! 344: break;
! 345: }
! 346: return SUCCESS;
! 347: }
! 348:
! 349: METHOD(task_t, process_i, status_t,
! 350: private_isakmp_natd_t *this, message_t *message)
! 351: {
! 352: status_t result = NEED_MORE;
! 353:
! 354: if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
! 355: { /* we didn't receive VIDs indicating support for NAT-T */
! 356: return SUCCESS;
! 357: }
! 358:
! 359: switch (message->get_exchange_type(message))
! 360: {
! 361: case ID_PROT:
! 362: { /* process NAT-D payloads in the second response, added them in the
! 363: * second request already, so we're done afterwards */
! 364: if (message->get_payload(message, PLV1_SECURITY_ASSOCIATION))
! 365: { /* wait for the second exchange */
! 366: return NEED_MORE;
! 367: }
! 368: result = SUCCESS;
! 369: /* fall */
! 370: }
! 371: case AGGRESSIVE:
! 372: { /* process NAT-D payloads in the first response, add them in the
! 373: * following second request */
! 374: process_payloads(this, message);
! 375:
! 376: if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
! 377: {
! 378: this->ike_sa->float_ports(this->ike_sa);
! 379: }
! 380: return result;
! 381: }
! 382: default:
! 383: break;
! 384: }
! 385: return SUCCESS;
! 386: }
! 387:
! 388: METHOD(task_t, process_r, status_t,
! 389: private_isakmp_natd_t *this, message_t *message)
! 390: {
! 391: status_t result = NEED_MORE;
! 392:
! 393: if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
! 394: { /* we didn't receive VIDs indicating NAT-T support */
! 395: return SUCCESS;
! 396: }
! 397:
! 398: switch (message->get_exchange_type(message))
! 399: {
! 400: case AGGRESSIVE:
! 401: { /* process NAT-D payloads in the second request, already added ours
! 402: * in the first response */
! 403: result = SUCCESS;
! 404: /* fall */
! 405: }
! 406: case ID_PROT:
! 407: { /* process NAT-D payloads in the second request, need to add ours
! 408: * to the second response */
! 409: if (message->get_payload(message, PLV1_SECURITY_ASSOCIATION))
! 410: { /* wait for the second exchange */
! 411: return NEED_MORE;
! 412: }
! 413: process_payloads(this, message);
! 414: return result;
! 415: }
! 416: default:
! 417: break;
! 418: }
! 419: return SUCCESS;
! 420: }
! 421:
! 422: METHOD(task_t, build_r, status_t,
! 423: private_isakmp_natd_t *this, message_t *message)
! 424: {
! 425: switch (message->get_exchange_type(message))
! 426: {
! 427: case ID_PROT:
! 428: { /* add NAT-D payloads to second response, already processed those
! 429: * contained in the second request */
! 430: if (message->get_payload(message, PLV1_SECURITY_ASSOCIATION))
! 431: { /* wait for the second exchange */
! 432: return NEED_MORE;
! 433: }
! 434: add_natd_payloads(this, message);
! 435: return SUCCESS;
! 436: }
! 437: case AGGRESSIVE:
! 438: { /* add NAT-D payloads to the first response, process those contained
! 439: * in the following second request */
! 440: add_natd_payloads(this, message);
! 441: return NEED_MORE;
! 442: }
! 443: default:
! 444: break;
! 445: }
! 446: return SUCCESS;
! 447: }
! 448:
! 449: METHOD(task_t, get_type, task_type_t,
! 450: private_isakmp_natd_t *this)
! 451: {
! 452: return TASK_ISAKMP_NATD;
! 453: }
! 454:
! 455: METHOD(task_t, migrate, void,
! 456: private_isakmp_natd_t *this, ike_sa_t *ike_sa)
! 457: {
! 458: this->ike_sa = ike_sa;
! 459: this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
! 460: this->src_seen = FALSE;
! 461: this->dst_seen = FALSE;
! 462: this->src_matched = FALSE;
! 463: this->dst_matched = FALSE;
! 464: }
! 465:
! 466: METHOD(task_t, destroy, void,
! 467: private_isakmp_natd_t *this)
! 468: {
! 469: free(this);
! 470: }
! 471:
! 472: /*
! 473: * Described in header.
! 474: */
! 475: isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator)
! 476: {
! 477: private_isakmp_natd_t *this;
! 478:
! 479: INIT(this,
! 480: .public = {
! 481: .task = {
! 482: .get_type = _get_type,
! 483: .migrate = _migrate,
! 484: .destroy = _destroy,
! 485: },
! 486: },
! 487: .ike_sa = ike_sa,
! 488: .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
! 489: .initiator = initiator,
! 490: );
! 491:
! 492: if (initiator)
! 493: {
! 494: this->public.task.build = _build_i;
! 495: this->public.task.process = _process_i;
! 496: }
! 497: else
! 498: {
! 499: this->public.task.build = _build_r;
! 500: this->public.task.process = _process_r;
! 501: }
! 502:
! 503: return &this->public;
! 504: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>