Annotation of embedaddon/strongswan/src/libcharon/sa/child_sa.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2006-2019 Tobias Brunner
! 3: * Copyright (C) 2016 Andreas Steffen
! 4: * Copyright (C) 2005-2008 Martin Willi
! 5: * Copyright (C) 2006 Daniel Roethlisberger
! 6: * Copyright (C) 2005 Jan Hutter
! 7: * HSR Hochschule fuer Technik Rapperswil
! 8: *
! 9: * This program is free software; you can redistribute it and/or modify it
! 10: * under the terms of the GNU General Public License as published by the
! 11: * Free Software Foundation; either version 2 of the License, or (at your
! 12: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 13: *
! 14: * This program is distributed in the hope that it will be useful, but
! 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 17: * for more details.
! 18: */
! 19:
! 20: #define _GNU_SOURCE
! 21: #include "child_sa.h"
! 22:
! 23: #include <stdio.h>
! 24: #include <string.h>
! 25: #include <time.h>
! 26:
! 27: #include <daemon.h>
! 28: #include <collections/array.h>
! 29:
! 30: ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
! 31: "CREATED",
! 32: "ROUTED",
! 33: "INSTALLING",
! 34: "INSTALLED",
! 35: "UPDATING",
! 36: "REKEYING",
! 37: "REKEYED",
! 38: "RETRYING",
! 39: "DELETING",
! 40: "DELETED",
! 41: "DESTROYING",
! 42: );
! 43:
! 44: ENUM_FLAGS(child_sa_outbound_state_names, CHILD_OUTBOUND_REGISTERED, CHILD_OUTBOUND_POLICIES,
! 45: "REGISTERED",
! 46: "SA",
! 47: "POLICIES",
! 48: );
! 49:
! 50: typedef struct private_child_sa_t private_child_sa_t;
! 51:
! 52: /**
! 53: * Private data of a child_sa_t object.
! 54: */
! 55: struct private_child_sa_t {
! 56: /**
! 57: * Public interface of child_sa_t.
! 58: */
! 59: child_sa_t public;
! 60:
! 61: /**
! 62: * address of us
! 63: */
! 64: host_t *my_addr;
! 65:
! 66: /**
! 67: * address of remote
! 68: */
! 69: host_t *other_addr;
! 70:
! 71: /**
! 72: * our actually used SPI, 0 if unused
! 73: */
! 74: uint32_t my_spi;
! 75:
! 76: /**
! 77: * others used SPI, 0 if unused
! 78: */
! 79: uint32_t other_spi;
! 80:
! 81: /**
! 82: * our Compression Parameter Index (CPI) used, 0 if unused
! 83: */
! 84: uint16_t my_cpi;
! 85:
! 86: /**
! 87: * others Compression Parameter Index (CPI) used, 0 if unused
! 88: */
! 89: uint16_t other_cpi;
! 90:
! 91: /**
! 92: * Array for local traffic selectors
! 93: */
! 94: array_t *my_ts;
! 95:
! 96: /**
! 97: * Array for remote traffic selectors
! 98: */
! 99: array_t *other_ts;
! 100:
! 101: /**
! 102: * Outbound encryption key cached during a rekeying
! 103: */
! 104: chunk_t encr_r;
! 105:
! 106: /**
! 107: * Outbound integrity key cached during a rekeying
! 108: */
! 109: chunk_t integ_r;
! 110:
! 111: /**
! 112: * Whether the outbound SA has only been registered yet during a rekeying
! 113: */
! 114: child_sa_outbound_state_t outbound_state;
! 115:
! 116: /**
! 117: * Whether the peer supports TFCv3
! 118: */
! 119: bool tfcv3;
! 120:
! 121: /**
! 122: * The outbound SPI of the CHILD_SA that replaced this one during a rekeying
! 123: */
! 124: uint32_t rekey_spi;
! 125:
! 126: /**
! 127: * Protocol used to protect this SA, ESP|AH
! 128: */
! 129: protocol_id_t protocol;
! 130:
! 131: /**
! 132: * reqid used for this child_sa
! 133: */
! 134: uint32_t reqid;
! 135:
! 136: /**
! 137: * Did we allocate/confirm and must release the reqid?
! 138: */
! 139: bool reqid_allocated;
! 140:
! 141: /**
! 142: * Is the reqid statically configured
! 143: */
! 144: bool static_reqid;
! 145:
! 146: /**
! 147: * Unique CHILD_SA identifier
! 148: */
! 149: uint32_t unique_id;
! 150:
! 151: /**
! 152: * Whether FWD policies in the outbound direction should be installed
! 153: */
! 154: bool policies_fwd_out;
! 155:
! 156: /**
! 157: * Inbound interface ID
! 158: */
! 159: uint32_t if_id_in;
! 160:
! 161: /**
! 162: * Outbound interface ID
! 163: */
! 164: uint32_t if_id_out;
! 165:
! 166: /**
! 167: * inbound mark used for this child_sa
! 168: */
! 169: mark_t mark_in;
! 170:
! 171: /**
! 172: * outbound mark used for this child_sa
! 173: */
! 174: mark_t mark_out;
! 175:
! 176: /**
! 177: * absolute time when rekeying is scheduled
! 178: */
! 179: time_t rekey_time;
! 180:
! 181: /**
! 182: * absolute time when the SA expires
! 183: */
! 184: time_t expire_time;
! 185:
! 186: /**
! 187: * absolute time when SA has been installed
! 188: */
! 189: time_t install_time;
! 190:
! 191: /**
! 192: * state of the CHILD_SA
! 193: */
! 194: child_sa_state_t state;
! 195:
! 196: /**
! 197: * TRUE if this CHILD_SA is used to install trap policies
! 198: */
! 199: bool trap;
! 200:
! 201: /**
! 202: * Specifies if UDP encapsulation is enabled (NAT traversal)
! 203: */
! 204: bool encap;
! 205:
! 206: /**
! 207: * Specifies the IPComp transform used (IPCOMP_NONE if disabled)
! 208: */
! 209: ipcomp_transform_t ipcomp;
! 210:
! 211: /**
! 212: * mode this SA uses, tunnel/transport
! 213: */
! 214: ipsec_mode_t mode;
! 215:
! 216: /**
! 217: * Action to enforce if peer closes the CHILD_SA
! 218: */
! 219: action_t close_action;
! 220:
! 221: /**
! 222: * Action to enforce if peer is considered dead
! 223: */
! 224: action_t dpd_action;
! 225:
! 226: /**
! 227: * selected proposal
! 228: */
! 229: proposal_t *proposal;
! 230:
! 231: /**
! 232: * config used to create this child
! 233: */
! 234: child_cfg_t *config;
! 235:
! 236: /**
! 237: * time of last use in seconds (inbound)
! 238: */
! 239: time_t my_usetime;
! 240:
! 241: /**
! 242: * time of last use in seconds (outbound)
! 243: */
! 244: time_t other_usetime;
! 245:
! 246: /**
! 247: * last number of inbound bytes
! 248: */
! 249: uint64_t my_usebytes;
! 250:
! 251: /**
! 252: * last number of outbound bytes
! 253: */
! 254: uint64_t other_usebytes;
! 255:
! 256: /**
! 257: * last number of inbound packets
! 258: */
! 259: uint64_t my_usepackets;
! 260:
! 261: /**
! 262: * last number of outbound bytes
! 263: */
! 264: uint64_t other_usepackets;
! 265: };
! 266:
! 267: /**
! 268: * Convert an IKEv2 specific protocol identifier to the IP protocol identifier
! 269: */
! 270: static inline uint8_t proto_ike2ip(protocol_id_t protocol)
! 271: {
! 272: switch (protocol)
! 273: {
! 274: case PROTO_ESP:
! 275: return IPPROTO_ESP;
! 276: case PROTO_AH:
! 277: return IPPROTO_AH;
! 278: default:
! 279: return protocol;
! 280: }
! 281: }
! 282:
! 283: /**
! 284: * Returns the mark to use on the inbound SA
! 285: */
! 286: static inline mark_t mark_in_sa(private_child_sa_t *this)
! 287: {
! 288: if (this->config->has_option(this->config, OPT_MARK_IN_SA))
! 289: {
! 290: return this->mark_in;
! 291: }
! 292: return (mark_t){};
! 293: }
! 294:
! 295: METHOD(child_sa_t, get_name, char*,
! 296: private_child_sa_t *this)
! 297: {
! 298: return this->config->get_name(this->config);
! 299: }
! 300:
! 301: METHOD(child_sa_t, get_reqid, uint32_t,
! 302: private_child_sa_t *this)
! 303: {
! 304: return this->reqid;
! 305: }
! 306:
! 307: METHOD(child_sa_t, get_unique_id, uint32_t,
! 308: private_child_sa_t *this)
! 309: {
! 310: return this->unique_id;
! 311: }
! 312:
! 313: METHOD(child_sa_t, get_config, child_cfg_t*,
! 314: private_child_sa_t *this)
! 315: {
! 316: return this->config;
! 317: }
! 318:
! 319: METHOD(child_sa_t, set_state, void,
! 320: private_child_sa_t *this, child_sa_state_t state)
! 321: {
! 322: if (this->state != state)
! 323: {
! 324: DBG2(DBG_CHD, "CHILD_SA %s{%d} state change: %N => %N",
! 325: get_name(this), this->unique_id,
! 326: child_sa_state_names, this->state,
! 327: child_sa_state_names, state);
! 328: charon->bus->child_state_change(charon->bus, &this->public, state);
! 329: this->state = state;
! 330: }
! 331: }
! 332:
! 333: METHOD(child_sa_t, get_state, child_sa_state_t,
! 334: private_child_sa_t *this)
! 335: {
! 336: return this->state;
! 337: }
! 338:
! 339: METHOD(child_sa_t, get_outbound_state, child_sa_outbound_state_t,
! 340: private_child_sa_t *this)
! 341: {
! 342: return this->outbound_state;
! 343: }
! 344:
! 345: METHOD(child_sa_t, get_spi, uint32_t,
! 346: private_child_sa_t *this, bool inbound)
! 347: {
! 348: return inbound ? this->my_spi : this->other_spi;
! 349: }
! 350:
! 351: METHOD(child_sa_t, get_cpi, uint16_t,
! 352: private_child_sa_t *this, bool inbound)
! 353: {
! 354: return inbound ? this->my_cpi : this->other_cpi;
! 355: }
! 356:
! 357: METHOD(child_sa_t, get_protocol, protocol_id_t,
! 358: private_child_sa_t *this)
! 359: {
! 360: return this->protocol;
! 361: }
! 362:
! 363: METHOD(child_sa_t, set_protocol, void,
! 364: private_child_sa_t *this, protocol_id_t protocol)
! 365: {
! 366: this->protocol = protocol;
! 367: }
! 368:
! 369: METHOD(child_sa_t, get_mode, ipsec_mode_t,
! 370: private_child_sa_t *this)
! 371: {
! 372: return this->mode;
! 373: }
! 374:
! 375: METHOD(child_sa_t, set_mode, void,
! 376: private_child_sa_t *this, ipsec_mode_t mode)
! 377: {
! 378: this->mode = mode;
! 379: }
! 380:
! 381: METHOD(child_sa_t, has_encap, bool,
! 382: private_child_sa_t *this)
! 383: {
! 384: return this->encap;
! 385: }
! 386:
! 387: METHOD(child_sa_t, get_ipcomp, ipcomp_transform_t,
! 388: private_child_sa_t *this)
! 389: {
! 390: return this->ipcomp;
! 391: }
! 392:
! 393: METHOD(child_sa_t, set_ipcomp, void,
! 394: private_child_sa_t *this, ipcomp_transform_t ipcomp)
! 395: {
! 396: this->ipcomp = ipcomp;
! 397: }
! 398:
! 399: METHOD(child_sa_t, set_close_action, void,
! 400: private_child_sa_t *this, action_t action)
! 401: {
! 402: this->close_action = action;
! 403: }
! 404:
! 405: METHOD(child_sa_t, get_close_action, action_t,
! 406: private_child_sa_t *this)
! 407: {
! 408: return this->close_action;
! 409: }
! 410:
! 411: METHOD(child_sa_t, set_dpd_action, void,
! 412: private_child_sa_t *this, action_t action)
! 413: {
! 414: this->dpd_action = action;
! 415: }
! 416:
! 417: METHOD(child_sa_t, get_dpd_action, action_t,
! 418: private_child_sa_t *this)
! 419: {
! 420: return this->dpd_action;
! 421: }
! 422:
! 423: METHOD(child_sa_t, get_proposal, proposal_t*,
! 424: private_child_sa_t *this)
! 425: {
! 426: return this->proposal;
! 427: }
! 428:
! 429: METHOD(child_sa_t, set_proposal, void,
! 430: private_child_sa_t *this, proposal_t *proposal)
! 431: {
! 432: this->proposal = proposal->clone(proposal, 0);
! 433: }
! 434:
! 435: METHOD(child_sa_t, create_ts_enumerator, enumerator_t*,
! 436: private_child_sa_t *this, bool local)
! 437: {
! 438: if (local)
! 439: {
! 440: return array_create_enumerator(this->my_ts);
! 441: }
! 442: return array_create_enumerator(this->other_ts);
! 443: }
! 444:
! 445: typedef struct policy_enumerator_t policy_enumerator_t;
! 446:
! 447: /**
! 448: * Private policy enumerator
! 449: */
! 450: struct policy_enumerator_t {
! 451: /** implements enumerator_t */
! 452: enumerator_t public;
! 453: /** enumerator over own TS */
! 454: enumerator_t *mine;
! 455: /** enumerator over others TS */
! 456: enumerator_t *other;
! 457: /** array of others TS, to recreate enumerator */
! 458: array_t *array;
! 459: /** currently enumerating TS for "me" side */
! 460: traffic_selector_t *ts;
! 461: };
! 462:
! 463: METHOD(enumerator_t, policy_enumerate, bool,
! 464: policy_enumerator_t *this, va_list args)
! 465: {
! 466: traffic_selector_t *other_ts, **my_out, **other_out;
! 467:
! 468: VA_ARGS_VGET(args, my_out, other_out);
! 469:
! 470: while (this->ts || this->mine->enumerate(this->mine, &this->ts))
! 471: {
! 472: if (!this->other->enumerate(this->other, &other_ts))
! 473: { /* end of others list, restart with new of mine */
! 474: this->other->destroy(this->other);
! 475: this->other = array_create_enumerator(this->array);
! 476: this->ts = NULL;
! 477: continue;
! 478: }
! 479: if (this->ts->get_type(this->ts) != other_ts->get_type(other_ts))
! 480: { /* family mismatch */
! 481: continue;
! 482: }
! 483: if (this->ts->get_protocol(this->ts) &&
! 484: other_ts->get_protocol(other_ts) &&
! 485: this->ts->get_protocol(this->ts) != other_ts->get_protocol(other_ts))
! 486: { /* protocol mismatch */
! 487: continue;
! 488: }
! 489: if (my_out)
! 490: {
! 491: *my_out = this->ts;
! 492: }
! 493: if (other_out)
! 494: {
! 495: *other_out = other_ts;
! 496: }
! 497: return TRUE;
! 498: }
! 499: return FALSE;
! 500: }
! 501:
! 502: METHOD(enumerator_t, policy_destroy, void,
! 503: policy_enumerator_t *this)
! 504: {
! 505: this->mine->destroy(this->mine);
! 506: this->other->destroy(this->other);
! 507: free(this);
! 508: }
! 509:
! 510: METHOD(child_sa_t, create_policy_enumerator, enumerator_t*,
! 511: private_child_sa_t *this)
! 512: {
! 513: policy_enumerator_t *e;
! 514:
! 515: INIT(e,
! 516: .public = {
! 517: .enumerate = enumerator_enumerate_default,
! 518: .venumerate = _policy_enumerate,
! 519: .destroy = _policy_destroy,
! 520: },
! 521: .mine = array_create_enumerator(this->my_ts),
! 522: .other = array_create_enumerator(this->other_ts),
! 523: .array = this->other_ts,
! 524: .ts = NULL,
! 525: );
! 526:
! 527: return &e->public;
! 528: }
! 529:
! 530: /**
! 531: * update the cached usebytes
! 532: * returns SUCCESS if the usebytes have changed, FAILED if not or no SPIs
! 533: * are available, and NOT_SUPPORTED if the kernel interface does not support
! 534: * querying the usebytes.
! 535: */
! 536: static status_t update_usebytes(private_child_sa_t *this, bool inbound)
! 537: {
! 538: status_t status = FAILED;
! 539: uint64_t bytes, packets;
! 540: time_t time;
! 541:
! 542: if (inbound)
! 543: {
! 544: if (this->my_spi)
! 545: {
! 546: kernel_ipsec_sa_id_t id = {
! 547: .src = this->other_addr,
! 548: .dst = this->my_addr,
! 549: .spi = this->my_spi,
! 550: .proto = proto_ike2ip(this->protocol),
! 551: .mark = mark_in_sa(this),
! 552: .if_id = this->if_id_in,
! 553: };
! 554: kernel_ipsec_query_sa_t query = {};
! 555:
! 556: status = charon->kernel->query_sa(charon->kernel, &id, &query,
! 557: &bytes, &packets, &time);
! 558: if (status == SUCCESS)
! 559: {
! 560: if (bytes > this->my_usebytes)
! 561: {
! 562: this->my_usebytes = bytes;
! 563: this->my_usepackets = packets;
! 564: if (time)
! 565: {
! 566: this->my_usetime = time;
! 567: }
! 568: }
! 569: else
! 570: {
! 571: status = FAILED;
! 572: }
! 573: }
! 574: }
! 575: }
! 576: else
! 577: {
! 578: if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
! 579: {
! 580: kernel_ipsec_sa_id_t id = {
! 581: .src = this->my_addr,
! 582: .dst = this->other_addr,
! 583: .spi = this->other_spi,
! 584: .proto = proto_ike2ip(this->protocol),
! 585: .mark = this->mark_out,
! 586: .if_id = this->if_id_out,
! 587: };
! 588: kernel_ipsec_query_sa_t query = {};
! 589:
! 590: status = charon->kernel->query_sa(charon->kernel, &id, &query,
! 591: &bytes, &packets, &time);
! 592: if (status == SUCCESS)
! 593: {
! 594: if (bytes > this->other_usebytes)
! 595: {
! 596: this->other_usebytes = bytes;
! 597: this->other_usepackets = packets;
! 598: if (time)
! 599: {
! 600: this->other_usetime = time;
! 601: }
! 602: }
! 603: else
! 604: {
! 605: status = FAILED;
! 606: }
! 607: }
! 608: }
! 609: }
! 610: return status;
! 611: }
! 612:
! 613: /**
! 614: * updates the cached usetime
! 615: */
! 616: static bool update_usetime(private_child_sa_t *this, bool inbound)
! 617: {
! 618: enumerator_t *enumerator;
! 619: traffic_selector_t *my_ts, *other_ts;
! 620: time_t last_use = 0;
! 621:
! 622: enumerator = create_policy_enumerator(this);
! 623: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
! 624: {
! 625: time_t in, out, fwd;
! 626:
! 627: if (inbound)
! 628: {
! 629: kernel_ipsec_policy_id_t id = {
! 630: .dir = POLICY_IN,
! 631: .src_ts = other_ts,
! 632: .dst_ts = my_ts,
! 633: .mark = this->mark_in,
! 634: .if_id = this->if_id_in,
! 635: };
! 636: kernel_ipsec_query_policy_t query = {};
! 637:
! 638: if (charon->kernel->query_policy(charon->kernel, &id, &query,
! 639: &in) == SUCCESS)
! 640: {
! 641: last_use = max(last_use, in);
! 642: }
! 643: if (this->mode != MODE_TRANSPORT)
! 644: {
! 645: id.dir = POLICY_FWD;
! 646: if (charon->kernel->query_policy(charon->kernel, &id, &query,
! 647: &fwd) == SUCCESS)
! 648: {
! 649: last_use = max(last_use, fwd);
! 650: }
! 651: }
! 652: }
! 653: else
! 654: {
! 655: kernel_ipsec_policy_id_t id = {
! 656: .dir = POLICY_OUT,
! 657: .src_ts = my_ts,
! 658: .dst_ts = other_ts,
! 659: .mark = this->mark_out,
! 660: .if_id = this->if_id_out,
! 661: .interface = this->config->get_interface(this->config),
! 662: };
! 663: kernel_ipsec_query_policy_t query = {};
! 664:
! 665: if (charon->kernel->query_policy(charon->kernel, &id, &query,
! 666: &out) == SUCCESS)
! 667: {
! 668: last_use = max(last_use, out);
! 669: }
! 670: }
! 671: }
! 672: enumerator->destroy(enumerator);
! 673:
! 674: if (last_use == 0)
! 675: {
! 676: return FALSE;
! 677: }
! 678: if (inbound)
! 679: {
! 680: this->my_usetime = last_use;
! 681: }
! 682: else
! 683: {
! 684: this->other_usetime = last_use;
! 685: }
! 686: return TRUE;
! 687: }
! 688:
! 689: METHOD(child_sa_t, get_usestats, void,
! 690: private_child_sa_t *this, bool inbound,
! 691: time_t *time, uint64_t *bytes, uint64_t *packets)
! 692: {
! 693: if ((!bytes && !packets) || update_usebytes(this, inbound) != FAILED)
! 694: {
! 695: /* there was traffic since last update or the kernel interface
! 696: * does not support querying the number of usebytes.
! 697: */
! 698: if (time)
! 699: {
! 700: if (!update_usetime(this, inbound) && !bytes && !packets)
! 701: {
! 702: /* if policy query did not yield a usetime, query SAs instead */
! 703: update_usebytes(this, inbound);
! 704: }
! 705: }
! 706: }
! 707: if (time)
! 708: {
! 709: *time = inbound ? this->my_usetime : this->other_usetime;
! 710: }
! 711: if (bytes)
! 712: {
! 713: *bytes = inbound ? this->my_usebytes : this->other_usebytes;
! 714: }
! 715: if (packets)
! 716: {
! 717: *packets = inbound ? this->my_usepackets : this->other_usepackets;
! 718: }
! 719: }
! 720:
! 721: METHOD(child_sa_t, get_mark, mark_t,
! 722: private_child_sa_t *this, bool inbound)
! 723: {
! 724: return inbound ? this->mark_in : this->mark_out;
! 725: }
! 726:
! 727: METHOD(child_sa_t, get_if_id, uint32_t,
! 728: private_child_sa_t *this, bool inbound)
! 729: {
! 730: return inbound ? this->if_id_in : this->if_id_out;
! 731: }
! 732:
! 733: METHOD(child_sa_t, get_lifetime, time_t,
! 734: private_child_sa_t *this, bool hard)
! 735: {
! 736: return hard ? this->expire_time : this->rekey_time;
! 737: }
! 738:
! 739: METHOD(child_sa_t, get_installtime, time_t,
! 740: private_child_sa_t *this)
! 741: {
! 742: return this->install_time;
! 743: }
! 744:
! 745: METHOD(child_sa_t, alloc_spi, uint32_t,
! 746: private_child_sa_t *this, protocol_id_t protocol)
! 747: {
! 748: if (charon->kernel->get_spi(charon->kernel, this->other_addr, this->my_addr,
! 749: proto_ike2ip(protocol), &this->my_spi) == SUCCESS)
! 750: {
! 751: /* if we allocate a SPI, but then are unable to establish the SA, we
! 752: * need to know the protocol family to delete the partial SA */
! 753: this->protocol = protocol;
! 754: return this->my_spi;
! 755: }
! 756: return 0;
! 757: }
! 758:
! 759: METHOD(child_sa_t, alloc_cpi, uint16_t,
! 760: private_child_sa_t *this)
! 761: {
! 762: if (charon->kernel->get_cpi(charon->kernel, this->other_addr, this->my_addr,
! 763: &this->my_cpi) == SUCCESS)
! 764: {
! 765: return this->my_cpi;
! 766: }
! 767: return 0;
! 768: }
! 769:
! 770: /**
! 771: * Install the given SA in the kernel
! 772: */
! 773: static status_t install_internal(private_child_sa_t *this, chunk_t encr,
! 774: chunk_t integ, uint32_t spi, uint16_t cpi, bool initiator, bool inbound,
! 775: bool tfcv3)
! 776: {
! 777: uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
! 778: uint16_t esn = NO_EXT_SEQ_NUMBERS;
! 779: linked_list_t *my_ts, *other_ts, *src_ts, *dst_ts;
! 780: time_t now;
! 781: kernel_ipsec_sa_id_t id;
! 782: kernel_ipsec_add_sa_t sa;
! 783: lifetime_cfg_t *lifetime;
! 784: uint32_t tfc = 0;
! 785: host_t *src, *dst;
! 786: status_t status;
! 787: bool update = FALSE;
! 788:
! 789: /* BEET requires the bound address from the traffic selectors */
! 790: my_ts = linked_list_create_from_enumerator(
! 791: array_create_enumerator(this->my_ts));
! 792: other_ts = linked_list_create_from_enumerator(
! 793: array_create_enumerator(this->other_ts));
! 794:
! 795: /* now we have to decide which spi to use. Use self allocated, if "in",
! 796: * or the one in the proposal, if not "in" (others). Additionally,
! 797: * source and dest host switch depending on the role */
! 798: if (inbound)
! 799: {
! 800: dst = this->my_addr;
! 801: src = this->other_addr;
! 802: if (this->my_spi == spi)
! 803: { /* alloc_spi has been called, do an SA update */
! 804: update = TRUE;
! 805: }
! 806: this->my_spi = spi;
! 807: this->my_cpi = cpi;
! 808: dst_ts = my_ts;
! 809: src_ts = other_ts;
! 810: }
! 811: else
! 812: {
! 813: src = this->my_addr;
! 814: dst = this->other_addr;
! 815: this->other_spi = spi;
! 816: this->other_cpi = cpi;
! 817: src_ts = my_ts;
! 818: dst_ts = other_ts;
! 819:
! 820: if (tfcv3)
! 821: {
! 822: tfc = this->config->get_tfc(this->config);
! 823: }
! 824: this->outbound_state |= CHILD_OUTBOUND_SA;
! 825: }
! 826:
! 827: DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
! 828: protocol_id_names, this->protocol);
! 829:
! 830: /* send SA down to the kernel */
! 831: DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
! 832:
! 833: this->proposal->get_algorithm(this->proposal, ENCRYPTION_ALGORITHM,
! 834: &enc_alg, &size);
! 835: this->proposal->get_algorithm(this->proposal, INTEGRITY_ALGORITHM,
! 836: &int_alg, &size);
! 837: this->proposal->get_algorithm(this->proposal, EXTENDED_SEQUENCE_NUMBERS,
! 838: &esn, NULL);
! 839:
! 840: if (int_alg == AUTH_HMAC_SHA2_256_128 &&
! 841: this->config->has_option(this->config, OPT_SHA256_96))
! 842: {
! 843: DBG2(DBG_CHD, " using %N with 96-bit truncation",
! 844: integrity_algorithm_names, int_alg);
! 845: int_alg = AUTH_HMAC_SHA2_256_96;
! 846: }
! 847:
! 848: if (!this->reqid_allocated && !this->static_reqid)
! 849: {
! 850: status = charon->kernel->alloc_reqid(charon->kernel, my_ts, other_ts,
! 851: this->mark_in, this->mark_out, this->if_id_in,
! 852: this->if_id_out, &this->reqid);
! 853: if (status != SUCCESS)
! 854: {
! 855: my_ts->destroy(my_ts);
! 856: other_ts->destroy(other_ts);
! 857: return status;
! 858: }
! 859: this->reqid_allocated = TRUE;
! 860: }
! 861:
! 862: lifetime = this->config->get_lifetime(this->config, TRUE);
! 863:
! 864: now = time_monotonic(NULL);
! 865: if (lifetime->time.rekey)
! 866: {
! 867: if (this->rekey_time)
! 868: {
! 869: this->rekey_time = min(this->rekey_time, now + lifetime->time.rekey);
! 870: }
! 871: else
! 872: {
! 873: this->rekey_time = now + lifetime->time.rekey;
! 874: }
! 875: }
! 876: if (lifetime->time.life)
! 877: {
! 878: this->expire_time = now + lifetime->time.life;
! 879: }
! 880:
! 881: if (!lifetime->time.jitter && !inbound)
! 882: { /* avoid triggering multiple rekey events */
! 883: lifetime->time.rekey = 0;
! 884: }
! 885:
! 886: id = (kernel_ipsec_sa_id_t){
! 887: .src = src,
! 888: .dst = dst,
! 889: .spi = spi,
! 890: .proto = proto_ike2ip(this->protocol),
! 891: .mark = inbound ? mark_in_sa(this) : this->mark_out,
! 892: .if_id = inbound ? this->if_id_in : this->if_id_out,
! 893: };
! 894: sa = (kernel_ipsec_add_sa_t){
! 895: .reqid = this->reqid,
! 896: .mode = this->mode,
! 897: .src_ts = src_ts,
! 898: .dst_ts = dst_ts,
! 899: .interface = inbound ? NULL : this->config->get_interface(this->config),
! 900: .lifetime = lifetime,
! 901: .enc_alg = enc_alg,
! 902: .enc_key = encr,
! 903: .int_alg = int_alg,
! 904: .int_key = integ,
! 905: .replay_window = this->config->get_replay_window(this->config),
! 906: .tfc = tfc,
! 907: .ipcomp = this->ipcomp,
! 908: .cpi = cpi,
! 909: .encap = this->encap,
! 910: .hw_offload = this->config->get_hw_offload(this->config),
! 911: .mark = this->config->get_set_mark(this->config, inbound),
! 912: .esn = esn,
! 913: .copy_df = !this->config->has_option(this->config, OPT_NO_COPY_DF),
! 914: .copy_ecn = !this->config->has_option(this->config, OPT_NO_COPY_ECN),
! 915: .copy_dscp = this->config->get_copy_dscp(this->config),
! 916: .initiator = initiator,
! 917: .inbound = inbound,
! 918: .update = update,
! 919: };
! 920:
! 921: if (sa.mark.value == MARK_SAME)
! 922: {
! 923: sa.mark.value = inbound ? this->mark_in.value : this->mark_out.value;
! 924: }
! 925:
! 926: status = charon->kernel->add_sa(charon->kernel, &id, &sa);
! 927:
! 928: my_ts->destroy(my_ts);
! 929: other_ts->destroy(other_ts);
! 930: free(lifetime);
! 931:
! 932: return status;
! 933: }
! 934:
! 935: METHOD(child_sa_t, install, status_t,
! 936: private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
! 937: uint16_t cpi, bool initiator, bool inbound, bool tfcv3)
! 938: {
! 939: return install_internal(this, encr, integ, spi, cpi, initiator, inbound,
! 940: tfcv3);
! 941: }
! 942:
! 943: /**
! 944: * Check kernel interface if policy updates are required
! 945: */
! 946: static bool require_policy_update()
! 947: {
! 948: kernel_feature_t f;
! 949:
! 950: f = charon->kernel->get_features(charon->kernel);
! 951: return !(f & KERNEL_NO_POLICY_UPDATES);
! 952: }
! 953:
! 954: /**
! 955: * Prepare SA config to install/delete policies
! 956: */
! 957: static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa,
! 958: ipsec_sa_cfg_t *other_sa)
! 959: {
! 960: enumerator_t *enumerator;
! 961:
! 962: *my_sa = (ipsec_sa_cfg_t){
! 963: .mode = this->mode,
! 964: .reqid = this->reqid,
! 965: .ipcomp = {
! 966: .transform = this->ipcomp,
! 967: },
! 968: };
! 969: *other_sa = *my_sa;
! 970:
! 971: my_sa->ipcomp.cpi = this->my_cpi;
! 972: other_sa->ipcomp.cpi = this->other_cpi;
! 973:
! 974: if (this->protocol == PROTO_ESP)
! 975: {
! 976: my_sa->esp.use = TRUE;
! 977: my_sa->esp.spi = this->my_spi;
! 978: other_sa->esp.use = TRUE;
! 979: other_sa->esp.spi = this->other_spi;
! 980: }
! 981: else
! 982: {
! 983: my_sa->ah.use = TRUE;
! 984: my_sa->ah.spi = this->my_spi;
! 985: other_sa->ah.use = TRUE;
! 986: other_sa->ah.spi = this->other_spi;
! 987: }
! 988:
! 989: enumerator = create_policy_enumerator(this);
! 990: while (enumerator->enumerate(enumerator, NULL, NULL))
! 991: {
! 992: my_sa->policy_count++;
! 993: other_sa->policy_count++;
! 994: }
! 995: enumerator->destroy(enumerator);
! 996: }
! 997:
! 998: /**
! 999: * Install inbound policies: in, fwd
! 1000: */
! 1001: static status_t install_policies_inbound(private_child_sa_t *this,
! 1002: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
! 1003: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
! 1004: ipsec_sa_cfg_t *other_sa, policy_type_t type,
! 1005: policy_priority_t priority, uint32_t manual_prio)
! 1006: {
! 1007: kernel_ipsec_policy_id_t in_id = {
! 1008: .dir = POLICY_IN,
! 1009: .src_ts = other_ts,
! 1010: .dst_ts = my_ts,
! 1011: .mark = this->mark_in,
! 1012: .if_id = this->if_id_in,
! 1013: };
! 1014: kernel_ipsec_manage_policy_t in_policy = {
! 1015: .type = type,
! 1016: .prio = priority,
! 1017: .manual_prio = manual_prio,
! 1018: .src = other_addr,
! 1019: .dst = my_addr,
! 1020: .sa = my_sa,
! 1021: };
! 1022: status_t status = SUCCESS;
! 1023:
! 1024: status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
! 1025: if (this->mode != MODE_TRANSPORT)
! 1026: {
! 1027: in_id.dir = POLICY_FWD;
! 1028: status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
! 1029: }
! 1030: return status;
! 1031: }
! 1032:
! 1033: /**
! 1034: * Install outbound policies: out, [fwd]
! 1035: */
! 1036: static status_t install_policies_outbound(private_child_sa_t *this,
! 1037: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
! 1038: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
! 1039: ipsec_sa_cfg_t *other_sa, policy_type_t type,
! 1040: policy_priority_t priority, uint32_t manual_prio)
! 1041: {
! 1042: kernel_ipsec_policy_id_t out_id = {
! 1043: .dir = POLICY_OUT,
! 1044: .src_ts = my_ts,
! 1045: .dst_ts = other_ts,
! 1046: .mark = this->mark_out,
! 1047: .if_id = this->if_id_out,
! 1048: .interface = this->config->get_interface(this->config),
! 1049: };
! 1050: kernel_ipsec_manage_policy_t out_policy = {
! 1051: .type = type,
! 1052: .prio = priority,
! 1053: .manual_prio = manual_prio,
! 1054: .src = my_addr,
! 1055: .dst = other_addr,
! 1056: .sa = other_sa,
! 1057: };
! 1058: status_t status = SUCCESS;
! 1059:
! 1060: status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy);
! 1061:
! 1062: if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
! 1063: {
! 1064: /* install an "outbound" FWD policy in case there is a drop policy
! 1065: * matching outbound forwarded traffic, to allow another tunnel to use
! 1066: * the reversed subnets and do the same we don't set a reqid (this also
! 1067: * allows the kernel backend to distinguish between the two types of
! 1068: * FWD policies). To avoid problems with symmetrically overlapping
! 1069: * policies of two SAs we install them with reduced priority. As they
! 1070: * basically act as bypass policies for drop policies we use a higher
! 1071: * priority than is used for them. */
! 1072: out_id.dir = POLICY_FWD;
! 1073: other_sa->reqid = 0;
! 1074: if (priority == POLICY_PRIORITY_DEFAULT)
! 1075: {
! 1076: out_policy.prio = POLICY_PRIORITY_ROUTED;
! 1077: }
! 1078: status |= charon->kernel->add_policy(charon->kernel, &out_id,
! 1079: &out_policy);
! 1080: /* reset the reqid for any other further policies */
! 1081: other_sa->reqid = this->reqid;
! 1082: }
! 1083: return status;
! 1084: }
! 1085:
! 1086: /**
! 1087: * Install all policies
! 1088: */
! 1089: static status_t install_policies_internal(private_child_sa_t *this,
! 1090: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
! 1091: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
! 1092: ipsec_sa_cfg_t *other_sa, policy_type_t type,
! 1093: policy_priority_t priority, uint32_t manual_prio, bool outbound)
! 1094: {
! 1095: status_t status = SUCCESS;
! 1096:
! 1097: status |= install_policies_inbound(this, my_addr, other_addr, my_ts,
! 1098: other_ts, my_sa, other_sa, type, priority, manual_prio);
! 1099: if (outbound)
! 1100: {
! 1101: status |= install_policies_outbound(this, my_addr, other_addr, my_ts,
! 1102: other_ts, my_sa, other_sa, type, priority, manual_prio);
! 1103: }
! 1104: return status;
! 1105: }
! 1106:
! 1107: /**
! 1108: * Delete inbound policies: in, fwd
! 1109: */
! 1110: static void del_policies_inbound(private_child_sa_t *this,
! 1111: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
! 1112: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
! 1113: ipsec_sa_cfg_t *other_sa, policy_type_t type,
! 1114: policy_priority_t priority, uint32_t manual_prio)
! 1115: {
! 1116: kernel_ipsec_policy_id_t in_id = {
! 1117: .dir = POLICY_IN,
! 1118: .src_ts = other_ts,
! 1119: .dst_ts = my_ts,
! 1120: .mark = this->mark_in,
! 1121: .if_id = this->if_id_in,
! 1122: };
! 1123: kernel_ipsec_manage_policy_t in_policy = {
! 1124: .type = type,
! 1125: .prio = priority,
! 1126: .manual_prio = manual_prio,
! 1127: .src = other_addr,
! 1128: .dst = my_addr,
! 1129: .sa = my_sa,
! 1130: };
! 1131:
! 1132: charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
! 1133:
! 1134: if (this->mode != MODE_TRANSPORT)
! 1135: {
! 1136: in_id.dir = POLICY_FWD;
! 1137: charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
! 1138: }
! 1139: }
! 1140:
! 1141: /**
! 1142: * Delete outbound policies: out, [fwd]
! 1143: */
! 1144: static void del_policies_outbound(private_child_sa_t *this,
! 1145: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
! 1146: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
! 1147: ipsec_sa_cfg_t *other_sa, policy_type_t type,
! 1148: policy_priority_t priority, uint32_t manual_prio)
! 1149: {
! 1150: kernel_ipsec_policy_id_t out_id = {
! 1151: .dir = POLICY_OUT,
! 1152: .src_ts = my_ts,
! 1153: .dst_ts = other_ts,
! 1154: .mark = this->mark_out,
! 1155: .if_id = this->if_id_out,
! 1156: .interface = this->config->get_interface(this->config),
! 1157: };
! 1158: kernel_ipsec_manage_policy_t out_policy = {
! 1159: .type = type,
! 1160: .prio = priority,
! 1161: .manual_prio = manual_prio,
! 1162: .src = my_addr,
! 1163: .dst = other_addr,
! 1164: .sa = other_sa,
! 1165: };
! 1166:
! 1167: charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
! 1168:
! 1169: if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
! 1170: {
! 1171: out_id.dir = POLICY_FWD;
! 1172: other_sa->reqid = 0;
! 1173: if (priority == POLICY_PRIORITY_DEFAULT)
! 1174: {
! 1175: out_policy.prio = POLICY_PRIORITY_ROUTED;
! 1176: }
! 1177: charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
! 1178: other_sa->reqid = this->reqid;
! 1179: }
! 1180: }
! 1181:
! 1182: /**
! 1183: * Delete in- and outbound policies
! 1184: */
! 1185: static void del_policies_internal(private_child_sa_t *this,
! 1186: host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
! 1187: traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
! 1188: ipsec_sa_cfg_t *other_sa, policy_type_t type,
! 1189: policy_priority_t priority, uint32_t manual_prio, bool outbound)
! 1190: {
! 1191: if (outbound)
! 1192: {
! 1193: del_policies_outbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
! 1194: other_sa, type, priority, manual_prio);
! 1195: }
! 1196: del_policies_inbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
! 1197: other_sa, type, priority, manual_prio);
! 1198: }
! 1199:
! 1200: METHOD(child_sa_t, set_policies, void,
! 1201: private_child_sa_t *this, linked_list_t *my_ts_list,
! 1202: linked_list_t *other_ts_list)
! 1203: {
! 1204: enumerator_t *enumerator;
! 1205: traffic_selector_t *my_ts, *other_ts;
! 1206:
! 1207: if (array_count(this->my_ts))
! 1208: {
! 1209: array_destroy_offset(this->my_ts,
! 1210: offsetof(traffic_selector_t, destroy));
! 1211: this->my_ts = array_create(0, 0);
! 1212: }
! 1213: enumerator = my_ts_list->create_enumerator(my_ts_list);
! 1214: while (enumerator->enumerate(enumerator, &my_ts))
! 1215: {
! 1216: array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts));
! 1217: }
! 1218: enumerator->destroy(enumerator);
! 1219: array_sort(this->my_ts, (void*)traffic_selector_cmp, NULL);
! 1220:
! 1221: if (array_count(this->other_ts))
! 1222: {
! 1223: array_destroy_offset(this->other_ts,
! 1224: offsetof(traffic_selector_t, destroy));
! 1225: this->other_ts = array_create(0, 0);
! 1226: }
! 1227: enumerator = other_ts_list->create_enumerator(other_ts_list);
! 1228: while (enumerator->enumerate(enumerator, &other_ts))
! 1229: {
! 1230: array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts));
! 1231: }
! 1232: enumerator->destroy(enumerator);
! 1233: array_sort(this->other_ts, (void*)traffic_selector_cmp, NULL);
! 1234: }
! 1235:
! 1236: METHOD(child_sa_t, install_policies, status_t,
! 1237: private_child_sa_t *this)
! 1238: {
! 1239: enumerator_t *enumerator;
! 1240: linked_list_t *my_ts_list, *other_ts_list;
! 1241: traffic_selector_t *my_ts, *other_ts;
! 1242: status_t status = SUCCESS;
! 1243: bool install_outbound = FALSE;
! 1244:
! 1245: if (!this->reqid_allocated && !this->static_reqid)
! 1246: {
! 1247: my_ts_list = linked_list_create_from_enumerator(
! 1248: array_create_enumerator(this->my_ts));
! 1249: other_ts_list = linked_list_create_from_enumerator(
! 1250: array_create_enumerator(this->other_ts));
! 1251: status = charon->kernel->alloc_reqid(
! 1252: charon->kernel, my_ts_list, other_ts_list,
! 1253: this->mark_in, this->mark_out, this->if_id_in,
! 1254: this->if_id_out, &this->reqid);
! 1255: my_ts_list->destroy(my_ts_list);
! 1256: other_ts_list->destroy(other_ts_list);
! 1257: if (status != SUCCESS)
! 1258: {
! 1259: return status;
! 1260: }
! 1261: this->reqid_allocated = TRUE;
! 1262: }
! 1263:
! 1264: if (!(this->outbound_state & CHILD_OUTBOUND_REGISTERED))
! 1265: {
! 1266: install_outbound = TRUE;
! 1267: this->outbound_state |= CHILD_OUTBOUND_POLICIES;
! 1268: }
! 1269:
! 1270: if (!this->config->has_option(this->config, OPT_NO_POLICIES))
! 1271: {
! 1272: policy_priority_t priority;
! 1273: ipsec_sa_cfg_t my_sa, other_sa;
! 1274: uint32_t manual_prio;
! 1275:
! 1276: prepare_sa_cfg(this, &my_sa, &other_sa);
! 1277: manual_prio = this->config->get_manual_prio(this->config);
! 1278:
! 1279: /* if we're not in state CHILD_INSTALLING (i.e. if there is no SAD
! 1280: * entry) we install a trap policy */
! 1281: this->trap = this->state == CHILD_CREATED;
! 1282: priority = this->trap ? POLICY_PRIORITY_ROUTED
! 1283: : POLICY_PRIORITY_DEFAULT;
! 1284:
! 1285: /* enumerate pairs of traffic selectors */
! 1286: enumerator = create_policy_enumerator(this);
! 1287: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
! 1288: {
! 1289: status |= install_policies_internal(this, this->my_addr,
! 1290: this->other_addr, my_ts, other_ts,
! 1291: &my_sa, &other_sa, POLICY_IPSEC, priority,
! 1292: manual_prio, install_outbound);
! 1293: if (status != SUCCESS)
! 1294: {
! 1295: break;
! 1296: }
! 1297: }
! 1298: enumerator->destroy(enumerator);
! 1299: }
! 1300:
! 1301: if (status == SUCCESS && this->trap)
! 1302: {
! 1303: set_state(this, CHILD_ROUTED);
! 1304: }
! 1305: return status;
! 1306: }
! 1307:
! 1308: METHOD(child_sa_t, register_outbound, status_t,
! 1309: private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
! 1310: uint16_t cpi, bool tfcv3)
! 1311: {
! 1312: status_t status;
! 1313:
! 1314: /* if the kernel supports installing SPIs with policies we install the
! 1315: * SA immediately as it will only be used once we update the policies */
! 1316: if (charon->kernel->get_features(charon->kernel) & KERNEL_POLICY_SPI)
! 1317: {
! 1318: status = install_internal(this, encr, integ, spi, cpi, FALSE, FALSE,
! 1319: tfcv3);
! 1320: }
! 1321: else
! 1322: {
! 1323: DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names,
! 1324: this->protocol);
! 1325: DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr,
! 1326: this->other_addr);
! 1327:
! 1328: this->other_spi = spi;
! 1329: this->other_cpi = cpi;
! 1330: this->encr_r = chunk_clone(encr);
! 1331: this->integ_r = chunk_clone(integ);
! 1332: this->tfcv3 = tfcv3;
! 1333: status = SUCCESS;
! 1334: }
! 1335: this->outbound_state |= CHILD_OUTBOUND_REGISTERED;
! 1336: return status;
! 1337: }
! 1338:
! 1339: METHOD(child_sa_t, install_outbound, status_t,
! 1340: private_child_sa_t *this)
! 1341: {
! 1342: enumerator_t *enumerator;
! 1343: traffic_selector_t *my_ts, *other_ts;
! 1344: status_t status = SUCCESS;
! 1345:
! 1346: if (!(this->outbound_state & CHILD_OUTBOUND_SA))
! 1347: {
! 1348: status = install_internal(this, this->encr_r, this->integ_r,
! 1349: this->other_spi, this->other_cpi, FALSE,
! 1350: FALSE, this->tfcv3);
! 1351: chunk_clear(&this->encr_r);
! 1352: chunk_clear(&this->integ_r);
! 1353: }
! 1354: this->outbound_state &= ~CHILD_OUTBOUND_REGISTERED;
! 1355: if (status != SUCCESS)
! 1356: {
! 1357: return status;
! 1358: }
! 1359: if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
! 1360: !(this->outbound_state & CHILD_OUTBOUND_POLICIES))
! 1361: {
! 1362: ipsec_sa_cfg_t my_sa, other_sa;
! 1363: uint32_t manual_prio;
! 1364:
! 1365: prepare_sa_cfg(this, &my_sa, &other_sa);
! 1366: manual_prio = this->config->get_manual_prio(this->config);
! 1367:
! 1368: enumerator = create_policy_enumerator(this);
! 1369: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
! 1370: {
! 1371: status |= install_policies_outbound(this, this->my_addr,
! 1372: this->other_addr, my_ts, other_ts,
! 1373: &my_sa, &other_sa, POLICY_IPSEC,
! 1374: POLICY_PRIORITY_DEFAULT, manual_prio);
! 1375: if (status != SUCCESS)
! 1376: {
! 1377: break;
! 1378: }
! 1379: }
! 1380: enumerator->destroy(enumerator);
! 1381: }
! 1382: this->outbound_state |= CHILD_OUTBOUND_POLICIES;
! 1383: return status;
! 1384: }
! 1385:
! 1386: METHOD(child_sa_t, remove_outbound, void,
! 1387: private_child_sa_t *this)
! 1388: {
! 1389: enumerator_t *enumerator;
! 1390: traffic_selector_t *my_ts, *other_ts;
! 1391:
! 1392: if (!(this->outbound_state & CHILD_OUTBOUND_SA))
! 1393: {
! 1394: if (this->outbound_state & CHILD_OUTBOUND_REGISTERED)
! 1395: {
! 1396: chunk_clear(&this->encr_r);
! 1397: chunk_clear(&this->integ_r);
! 1398: this->outbound_state = CHILD_OUTBOUND_NONE;
! 1399: }
! 1400: return;
! 1401: }
! 1402:
! 1403: if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
! 1404: (this->outbound_state & CHILD_OUTBOUND_POLICIES))
! 1405: {
! 1406: ipsec_sa_cfg_t my_sa, other_sa;
! 1407: uint32_t manual_prio;
! 1408:
! 1409: prepare_sa_cfg(this, &my_sa, &other_sa);
! 1410: manual_prio = this->config->get_manual_prio(this->config);
! 1411:
! 1412: enumerator = create_policy_enumerator(this);
! 1413: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
! 1414: {
! 1415: del_policies_outbound(this, this->my_addr, this->other_addr,
! 1416: my_ts, other_ts, &my_sa, &other_sa,
! 1417: POLICY_IPSEC, POLICY_PRIORITY_DEFAULT,
! 1418: manual_prio);
! 1419: }
! 1420: enumerator->destroy(enumerator);
! 1421: }
! 1422:
! 1423: kernel_ipsec_sa_id_t id = {
! 1424: .src = this->my_addr,
! 1425: .dst = this->other_addr,
! 1426: .spi = this->other_spi,
! 1427: .proto = proto_ike2ip(this->protocol),
! 1428: .mark = this->mark_out,
! 1429: .if_id = this->if_id_out,
! 1430: };
! 1431: kernel_ipsec_del_sa_t sa = {
! 1432: .cpi = this->other_cpi,
! 1433: };
! 1434: charon->kernel->del_sa(charon->kernel, &id, &sa);
! 1435: this->outbound_state = CHILD_OUTBOUND_NONE;
! 1436: }
! 1437:
! 1438: METHOD(child_sa_t, set_rekey_spi, void,
! 1439: private_child_sa_t *this, uint32_t spi)
! 1440: {
! 1441: this->rekey_spi = spi;
! 1442: }
! 1443:
! 1444: METHOD(child_sa_t, get_rekey_spi, uint32_t,
! 1445: private_child_sa_t *this)
! 1446: {
! 1447: return this->rekey_spi;
! 1448: }
! 1449:
! 1450: CALLBACK(reinstall_vip, void,
! 1451: host_t *vip, va_list args)
! 1452: {
! 1453: host_t *me;
! 1454: char *iface;
! 1455:
! 1456: VA_ARGS_VGET(args, me);
! 1457: if (charon->kernel->get_interface(charon->kernel, me, &iface))
! 1458: {
! 1459: charon->kernel->del_ip(charon->kernel, vip, -1, TRUE);
! 1460: charon->kernel->add_ip(charon->kernel, vip, -1, iface);
! 1461: free(iface);
! 1462: }
! 1463: }
! 1464:
! 1465: /**
! 1466: * Update addresses and encap state of IPsec SAs in the kernel
! 1467: */
! 1468: static status_t update_sas(private_child_sa_t *this, host_t *me, host_t *other,
! 1469: bool encap)
! 1470: {
! 1471: /* update our (initiator) SA */
! 1472: if (this->my_spi)
! 1473: {
! 1474: kernel_ipsec_sa_id_t id = {
! 1475: .src = this->other_addr,
! 1476: .dst = this->my_addr,
! 1477: .spi = this->my_spi,
! 1478: .proto = proto_ike2ip(this->protocol),
! 1479: .mark = mark_in_sa(this),
! 1480: .if_id = this->if_id_in,
! 1481: };
! 1482: kernel_ipsec_update_sa_t sa = {
! 1483: .cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
! 1484: .new_src = other,
! 1485: .new_dst = me,
! 1486: .encap = this->encap,
! 1487: .new_encap = encap,
! 1488: };
! 1489: if (charon->kernel->update_sa(charon->kernel, &id,
! 1490: &sa) == NOT_SUPPORTED)
! 1491: {
! 1492: return NOT_SUPPORTED;
! 1493: }
! 1494: }
! 1495:
! 1496: /* update his (responder) SA */
! 1497: if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
! 1498: {
! 1499: kernel_ipsec_sa_id_t id = {
! 1500: .src = this->my_addr,
! 1501: .dst = this->other_addr,
! 1502: .spi = this->other_spi,
! 1503: .proto = proto_ike2ip(this->protocol),
! 1504: .mark = this->mark_out,
! 1505: .if_id = this->if_id_out,
! 1506: };
! 1507: kernel_ipsec_update_sa_t sa = {
! 1508: .cpi = this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
! 1509: .new_src = me,
! 1510: .new_dst = other,
! 1511: .encap = this->encap,
! 1512: .new_encap = encap,
! 1513: };
! 1514: if (charon->kernel->update_sa(charon->kernel, &id,
! 1515: &sa) == NOT_SUPPORTED)
! 1516: {
! 1517: return NOT_SUPPORTED;
! 1518: }
! 1519: }
! 1520: /* we currently ignore the actual return values above */
! 1521: return SUCCESS;
! 1522: }
! 1523:
! 1524: METHOD(child_sa_t, update, status_t,
! 1525: private_child_sa_t *this, host_t *me, host_t *other, linked_list_t *vips,
! 1526: bool encap)
! 1527: {
! 1528: child_sa_state_t old;
! 1529: bool transport_proxy_mode;
! 1530:
! 1531: /* anything changed at all? */
! 1532: if (me->equals(me, this->my_addr) &&
! 1533: other->equals(other, this->other_addr) && this->encap == encap)
! 1534: {
! 1535: return SUCCESS;
! 1536: }
! 1537:
! 1538: old = this->state;
! 1539: set_state(this, CHILD_UPDATING);
! 1540: transport_proxy_mode = this->mode == MODE_TRANSPORT &&
! 1541: this->config->has_option(this->config,
! 1542: OPT_PROXY_MODE);
! 1543:
! 1544: if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
! 1545: require_policy_update())
! 1546: {
! 1547: ipsec_sa_cfg_t my_sa, other_sa;
! 1548: enumerator_t *enumerator;
! 1549: traffic_selector_t *my_ts, *other_ts;
! 1550: uint32_t manual_prio;
! 1551: status_t state;
! 1552: bool outbound;
! 1553:
! 1554: prepare_sa_cfg(this, &my_sa, &other_sa);
! 1555: manual_prio = this->config->get_manual_prio(this->config);
! 1556: outbound = (this->outbound_state & CHILD_OUTBOUND_POLICIES);
! 1557:
! 1558: enumerator = create_policy_enumerator(this);
! 1559: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
! 1560: {
! 1561: /* install drop policy to avoid traffic leaks, acquires etc. */
! 1562: if (outbound)
! 1563: {
! 1564: install_policies_outbound(this, this->my_addr, this->other_addr,
! 1565: my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP,
! 1566: POLICY_PRIORITY_DEFAULT, manual_prio);
! 1567: }
! 1568: /* remove old policies */
! 1569: del_policies_internal(this, this->my_addr, this->other_addr,
! 1570: my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC,
! 1571: POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
! 1572: }
! 1573: enumerator->destroy(enumerator);
! 1574:
! 1575: /* update the IPsec SAs */
! 1576: state = update_sas(this, me, other, encap);
! 1577:
! 1578: enumerator = create_policy_enumerator(this);
! 1579: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
! 1580: {
! 1581: traffic_selector_t *old_my_ts = NULL, *old_other_ts = NULL;
! 1582:
! 1583: /* reinstall the previous policies if we can't update the SAs */
! 1584: if (state == NOT_SUPPORTED)
! 1585: {
! 1586: install_policies_internal(this, this->my_addr, this->other_addr,
! 1587: my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC,
! 1588: POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
! 1589: }
! 1590: else
! 1591: {
! 1592: /* check if we have to update a "dynamic" traffic selector */
! 1593: if (!me->ip_equals(me, this->my_addr) &&
! 1594: my_ts->is_host(my_ts, this->my_addr))
! 1595: {
! 1596: old_my_ts = my_ts->clone(my_ts);
! 1597: my_ts->set_address(my_ts, me);
! 1598: }
! 1599: if (!other->ip_equals(other, this->other_addr) &&
! 1600: other_ts->is_host(other_ts, this->other_addr))
! 1601: {
! 1602: old_other_ts = other_ts->clone(other_ts);
! 1603: other_ts->set_address(other_ts, other);
! 1604: }
! 1605:
! 1606: /* we reinstall the virtual IP to handle interface roaming
! 1607: * correctly */
! 1608: vips->invoke_function(vips, reinstall_vip, me);
! 1609:
! 1610: /* reinstall updated policies */
! 1611: install_policies_internal(this, me, other, my_ts, other_ts,
! 1612: &my_sa, &other_sa, POLICY_IPSEC,
! 1613: POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
! 1614: }
! 1615: /* remove the drop policy */
! 1616: if (outbound)
! 1617: {
! 1618: del_policies_outbound(this, this->my_addr, this->other_addr,
! 1619: old_my_ts ?: my_ts, old_other_ts ?: other_ts,
! 1620: &my_sa, &other_sa, POLICY_DROP,
! 1621: POLICY_PRIORITY_DEFAULT, manual_prio);
! 1622: }
! 1623:
! 1624: DESTROY_IF(old_my_ts);
! 1625: DESTROY_IF(old_other_ts);
! 1626: }
! 1627: enumerator->destroy(enumerator);
! 1628:
! 1629: if (state == NOT_SUPPORTED)
! 1630: {
! 1631: set_state(this, old);
! 1632: return NOT_SUPPORTED;
! 1633: }
! 1634:
! 1635: }
! 1636: else if (!transport_proxy_mode)
! 1637: {
! 1638: if (update_sas(this, me, other, encap) == NOT_SUPPORTED)
! 1639: {
! 1640: set_state(this, old);
! 1641: return NOT_SUPPORTED;
! 1642: }
! 1643: }
! 1644:
! 1645: if (!transport_proxy_mode)
! 1646: {
! 1647: /* apply hosts */
! 1648: if (!me->equals(me, this->my_addr))
! 1649: {
! 1650: this->my_addr->destroy(this->my_addr);
! 1651: this->my_addr = me->clone(me);
! 1652: }
! 1653: if (!other->equals(other, this->other_addr))
! 1654: {
! 1655: this->other_addr->destroy(this->other_addr);
! 1656: this->other_addr = other->clone(other);
! 1657: }
! 1658: }
! 1659:
! 1660: this->encap = encap;
! 1661: set_state(this, old);
! 1662:
! 1663: return SUCCESS;
! 1664: }
! 1665:
! 1666: METHOD(child_sa_t, destroy, void,
! 1667: private_child_sa_t *this)
! 1668: {
! 1669: enumerator_t *enumerator;
! 1670: traffic_selector_t *my_ts, *other_ts;
! 1671: policy_priority_t priority;
! 1672:
! 1673: priority = this->trap ? POLICY_PRIORITY_ROUTED : POLICY_PRIORITY_DEFAULT;
! 1674:
! 1675: set_state(this, CHILD_DESTROYING);
! 1676:
! 1677: if (!this->config->has_option(this->config, OPT_NO_POLICIES))
! 1678: {
! 1679: ipsec_sa_cfg_t my_sa, other_sa;
! 1680: uint32_t manual_prio;
! 1681: bool del_outbound;
! 1682:
! 1683: prepare_sa_cfg(this, &my_sa, &other_sa);
! 1684: manual_prio = this->config->get_manual_prio(this->config);
! 1685: del_outbound = (this->outbound_state & CHILD_OUTBOUND_POLICIES) ||
! 1686: this->trap;
! 1687:
! 1688: /* delete all policies in the kernel */
! 1689: enumerator = create_policy_enumerator(this);
! 1690: while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
! 1691: {
! 1692: del_policies_internal(this, this->my_addr,
! 1693: this->other_addr, my_ts, other_ts, &my_sa, &other_sa,
! 1694: POLICY_IPSEC, priority, manual_prio, del_outbound);
! 1695: }
! 1696: enumerator->destroy(enumerator);
! 1697: }
! 1698:
! 1699: /* delete SAs in the kernel, if they are set up */
! 1700: if (this->my_spi)
! 1701: {
! 1702: kernel_ipsec_sa_id_t id = {
! 1703: .src = this->other_addr,
! 1704: .dst = this->my_addr,
! 1705: .spi = this->my_spi,
! 1706: .proto = proto_ike2ip(this->protocol),
! 1707: .mark = mark_in_sa(this),
! 1708: .if_id = this->if_id_in,
! 1709: };
! 1710: kernel_ipsec_del_sa_t sa = {
! 1711: .cpi = this->my_cpi,
! 1712: };
! 1713: charon->kernel->del_sa(charon->kernel, &id, &sa);
! 1714: }
! 1715: if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
! 1716: {
! 1717: kernel_ipsec_sa_id_t id = {
! 1718: .src = this->my_addr,
! 1719: .dst = this->other_addr,
! 1720: .spi = this->other_spi,
! 1721: .proto = proto_ike2ip(this->protocol),
! 1722: .mark = this->mark_out,
! 1723: .if_id = this->if_id_out,
! 1724: };
! 1725: kernel_ipsec_del_sa_t sa = {
! 1726: .cpi = this->other_cpi,
! 1727: };
! 1728: charon->kernel->del_sa(charon->kernel, &id, &sa);
! 1729: }
! 1730:
! 1731: if (this->reqid_allocated)
! 1732: {
! 1733: if (charon->kernel->release_reqid(charon->kernel,
! 1734: this->reqid, this->mark_in, this->mark_out,
! 1735: this->if_id_in, this->if_id_out) != SUCCESS)
! 1736: {
! 1737: DBG1(DBG_CHD, "releasing reqid %u failed", this->reqid);
! 1738: }
! 1739: }
! 1740:
! 1741: array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
! 1742: array_destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
! 1743: this->my_addr->destroy(this->my_addr);
! 1744: this->other_addr->destroy(this->other_addr);
! 1745: DESTROY_IF(this->proposal);
! 1746: this->config->destroy(this->config);
! 1747: chunk_clear(&this->encr_r);
! 1748: chunk_clear(&this->integ_r);
! 1749: free(this);
! 1750: }
! 1751:
! 1752: /**
! 1753: * Get proxy address for one side, if any
! 1754: */
! 1755: static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
! 1756: {
! 1757: host_t *host = NULL;
! 1758: uint8_t mask;
! 1759: enumerator_t *enumerator;
! 1760: linked_list_t *ts_list, *list;
! 1761: traffic_selector_t *ts;
! 1762:
! 1763: list = linked_list_create_with_items(ike, NULL);
! 1764: ts_list = config->get_traffic_selectors(config, local, NULL, list, FALSE);
! 1765: list->destroy(list);
! 1766:
! 1767: enumerator = ts_list->create_enumerator(ts_list);
! 1768: while (enumerator->enumerate(enumerator, &ts))
! 1769: {
! 1770: if (ts->is_host(ts, NULL) && ts->to_subnet(ts, &host, &mask))
! 1771: {
! 1772: DBG1(DBG_CHD, "%s address: %H is a transport mode proxy for %H",
! 1773: local ? "my" : "other", ike, host);
! 1774: break;
! 1775: }
! 1776: }
! 1777: enumerator->destroy(enumerator);
! 1778: ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
! 1779:
! 1780: if (!host)
! 1781: {
! 1782: host = ike->clone(ike);
! 1783: }
! 1784: return host;
! 1785: }
! 1786:
! 1787: /*
! 1788: * Described in header
! 1789: */
! 1790: child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
! 1791: child_sa_create_t *data)
! 1792: {
! 1793: private_child_sa_t *this;
! 1794: static refcount_t unique_id = 0, unique_mark = 0;
! 1795:
! 1796: INIT(this,
! 1797: .public = {
! 1798: .get_name = _get_name,
! 1799: .get_reqid = _get_reqid,
! 1800: .get_unique_id = _get_unique_id,
! 1801: .get_config = _get_config,
! 1802: .get_state = _get_state,
! 1803: .set_state = _set_state,
! 1804: .get_outbound_state = _get_outbound_state,
! 1805: .get_spi = _get_spi,
! 1806: .get_cpi = _get_cpi,
! 1807: .get_protocol = _get_protocol,
! 1808: .set_protocol = _set_protocol,
! 1809: .get_mode = _get_mode,
! 1810: .set_mode = _set_mode,
! 1811: .get_proposal = _get_proposal,
! 1812: .set_proposal = _set_proposal,
! 1813: .get_lifetime = _get_lifetime,
! 1814: .get_installtime = _get_installtime,
! 1815: .get_usestats = _get_usestats,
! 1816: .get_mark = _get_mark,
! 1817: .get_if_id = _get_if_id,
! 1818: .has_encap = _has_encap,
! 1819: .get_ipcomp = _get_ipcomp,
! 1820: .set_ipcomp = _set_ipcomp,
! 1821: .get_close_action = _get_close_action,
! 1822: .set_close_action = _set_close_action,
! 1823: .get_dpd_action = _get_dpd_action,
! 1824: .set_dpd_action = _set_dpd_action,
! 1825: .alloc_spi = _alloc_spi,
! 1826: .alloc_cpi = _alloc_cpi,
! 1827: .install = _install,
! 1828: .register_outbound = _register_outbound,
! 1829: .install_outbound = _install_outbound,
! 1830: .remove_outbound = _remove_outbound,
! 1831: .set_rekey_spi = _set_rekey_spi,
! 1832: .get_rekey_spi = _get_rekey_spi,
! 1833: .update = _update,
! 1834: .set_policies = _set_policies,
! 1835: .install_policies = _install_policies,
! 1836: .create_ts_enumerator = _create_ts_enumerator,
! 1837: .create_policy_enumerator = _create_policy_enumerator,
! 1838: .destroy = _destroy,
! 1839: },
! 1840: .encap = data->encap,
! 1841: .ipcomp = IPCOMP_NONE,
! 1842: .state = CHILD_CREATED,
! 1843: .my_ts = array_create(0, 0),
! 1844: .other_ts = array_create(0, 0),
! 1845: .protocol = PROTO_NONE,
! 1846: .mode = MODE_TUNNEL,
! 1847: .close_action = config->get_close_action(config),
! 1848: .dpd_action = config->get_dpd_action(config),
! 1849: .reqid = config->get_reqid(config),
! 1850: .unique_id = ref_get(&unique_id),
! 1851: .mark_in = config->get_mark(config, TRUE),
! 1852: .mark_out = config->get_mark(config, FALSE),
! 1853: .if_id_in = config->get_if_id(config, TRUE) ?: data->if_id_in_def,
! 1854: .if_id_out = config->get_if_id(config, FALSE) ?: data->if_id_out_def,
! 1855: .install_time = time_monotonic(NULL),
! 1856: .policies_fwd_out = config->has_option(config, OPT_FWD_OUT_POLICIES),
! 1857: );
! 1858:
! 1859: this->config = config;
! 1860: config->get_ref(config);
! 1861:
! 1862: if (data->mark_in)
! 1863: {
! 1864: this->mark_in.value = data->mark_in;
! 1865: }
! 1866: if (data->mark_out)
! 1867: {
! 1868: this->mark_out.value = data->mark_out;
! 1869: }
! 1870: if (data->if_id_in)
! 1871: {
! 1872: this->if_id_in = data->if_id_in;
! 1873: }
! 1874: if (data->if_id_out)
! 1875: {
! 1876: this->if_id_out = data->if_id_out;
! 1877: }
! 1878:
! 1879: allocate_unique_if_ids(&this->if_id_in, &this->if_id_out);
! 1880:
! 1881: if (MARK_IS_UNIQUE(this->mark_in.value) ||
! 1882: MARK_IS_UNIQUE(this->mark_out.value))
! 1883: {
! 1884: refcount_t mark = 0;
! 1885: bool unique_dir = this->mark_in.value == MARK_UNIQUE_DIR ||
! 1886: this->mark_out.value == MARK_UNIQUE_DIR;
! 1887:
! 1888: if (!unique_dir)
! 1889: {
! 1890: mark = ref_get(&unique_mark);
! 1891: }
! 1892: if (MARK_IS_UNIQUE(this->mark_in.value))
! 1893: {
! 1894: this->mark_in.value = unique_dir ? ref_get(&unique_mark) : mark;
! 1895: }
! 1896: if (MARK_IS_UNIQUE(this->mark_out.value))
! 1897: {
! 1898: this->mark_out.value = unique_dir ? ref_get(&unique_mark) : mark;
! 1899: }
! 1900: }
! 1901:
! 1902: if (!this->reqid)
! 1903: {
! 1904: /* reuse old reqid if we are rekeying an existing CHILD_SA and when
! 1905: * initiating a trap policy. While the reqid cache would find the same
! 1906: * reqid for our selectors, this does not work in a special case: If an
! 1907: * SA is triggered by a trap policy, but the negotiated TS get
! 1908: * narrowed, we still must reuse the same reqid to successfully
! 1909: * replace the temporary SA on the kernel level. Rekeying such an SA
! 1910: * requires an explicit reqid, as the cache currently knows the original
! 1911: * selectors only for that reqid. */
! 1912: this->reqid = data->reqid;
! 1913: }
! 1914: else
! 1915: {
! 1916: this->static_reqid = TRUE;
! 1917: }
! 1918:
! 1919: /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
! 1920: if (config->get_mode(config) == MODE_TRANSPORT &&
! 1921: config->has_option(config, OPT_PROXY_MODE))
! 1922: {
! 1923: this->mode = MODE_TRANSPORT;
! 1924:
! 1925: this->my_addr = get_proxy_addr(config, me, TRUE);
! 1926: this->other_addr = get_proxy_addr(config, other, FALSE);
! 1927: }
! 1928: else
! 1929: {
! 1930: this->my_addr = me->clone(me);
! 1931: this->other_addr = other->clone(other);
! 1932: }
! 1933: return &this->public;
! 1934: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>