Annotation of embedaddon/strongswan/src/charon-cmd/cmd/cmd_connection.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2013 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2013 Martin Willi
! 6: * Copyright (C) 2013 revosec AG
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: #include "cmd_connection.h"
! 20:
! 21: #include <signal.h>
! 22: #include <unistd.h>
! 23:
! 24: #include <utils/debug.h>
! 25: #include <processing/jobs/callback_job.h>
! 26: #include <threading/thread.h>
! 27: #include <daemon.h>
! 28:
! 29: typedef enum profile_t profile_t;
! 30: typedef struct private_cmd_connection_t private_cmd_connection_t;
! 31:
! 32: /**
! 33: * Connection profiles we support
! 34: */
! 35: enum profile_t {
! 36: PROF_UNDEF,
! 37: PROF_V2_PUB,
! 38: PROF_V2_EAP,
! 39: PROF_V2_PUB_EAP,
! 40: PROF_V1_PUB,
! 41: PROF_V1_PUB_AM,
! 42: PROF_V1_XAUTH,
! 43: PROF_V1_XAUTH_AM,
! 44: PROF_V1_XAUTH_PSK,
! 45: PROF_V1_XAUTH_PSK_AM,
! 46: PROF_V1_HYBRID,
! 47: PROF_V1_HYBRID_AM,
! 48: };
! 49:
! 50: ENUM(profile_names, PROF_V2_PUB, PROF_V1_HYBRID_AM,
! 51: "ikev2-pub",
! 52: "ikev2-eap",
! 53: "ikev2-pub-eap",
! 54: "ikev1-pub",
! 55: "ikev1-pub-am",
! 56: "ikev1-xauth",
! 57: "ikev1-xauth-am",
! 58: "ikev1-xauth-psk",
! 59: "ikev1-xauth-psk-am",
! 60: "ikev1-hybrid",
! 61: "ikev1-hybrid-am",
! 62: );
! 63:
! 64: /**
! 65: * Private data of an cmd_connection_t object.
! 66: */
! 67: struct private_cmd_connection_t {
! 68:
! 69: /**
! 70: * Public cmd_connection_t interface.
! 71: */
! 72: cmd_connection_t public;
! 73:
! 74: /**
! 75: * Process ID to terminate on failure
! 76: */
! 77: pid_t pid;
! 78:
! 79: /**
! 80: * List of local traffic selectors
! 81: */
! 82: linked_list_t *local_ts;
! 83:
! 84: /**
! 85: * List of remote traffic selectors
! 86: */
! 87: linked_list_t *remote_ts;
! 88:
! 89: /**
! 90: * List of IKE proposals
! 91: */
! 92: linked_list_t *ike_proposals;
! 93:
! 94: /**
! 95: * List of CHILD proposals
! 96: */
! 97: linked_list_t *child_proposals;
! 98:
! 99: /**
! 100: * Hostname to connect to
! 101: */
! 102: char *host;
! 103:
! 104: /**
! 105: * Server identity, or NULL to use host
! 106: */
! 107: char *server;
! 108:
! 109: /**
! 110: * Local identity
! 111: */
! 112: char *identity;
! 113:
! 114: /**
! 115: * XAuth/EAP identity
! 116: */
! 117: char *xautheap;
! 118:
! 119: /**
! 120: * Is a private key configured
! 121: */
! 122: bool key_seen;
! 123:
! 124: /**
! 125: * Selected connection profile
! 126: */
! 127: profile_t profile;
! 128: };
! 129:
! 130: /**
! 131: * Shut down application
! 132: */
! 133: static void terminate(pid_t pid)
! 134: {
! 135: kill(pid, SIGUSR1);
! 136: }
! 137:
! 138: /**
! 139: * Create peer config with associated ike config
! 140: */
! 141: static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this)
! 142: {
! 143: ike_cfg_t *ike_cfg;
! 144: peer_cfg_t *peer_cfg;
! 145: proposal_t *proposal;
! 146: ike_cfg_create_t ike = {
! 147: .local = "0.0.0.0",
! 148: .remote = this->host,
! 149: .remote_port = IKEV2_UDP_PORT,
! 150: .fragmentation = FRAGMENTATION_YES,
! 151: };
! 152: peer_cfg_create_t peer = {
! 153: .cert_policy = CERT_SEND_IF_ASKED,
! 154: .unique = UNIQUE_REPLACE,
! 155: .keyingtries = 1,
! 156: .rekey_time = 36000, /* 10h */
! 157: .jitter_time = 600, /* 10min */
! 158: .over_time = 600, /* 10min */
! 159: .dpd = 30,
! 160: };
! 161:
! 162: switch (this->profile)
! 163: {
! 164: case PROF_UNDEF:
! 165: case PROF_V2_PUB:
! 166: case PROF_V2_EAP:
! 167: case PROF_V2_PUB_EAP:
! 168: ike.version = IKEV2;
! 169: break;
! 170: case PROF_V1_PUB_AM:
! 171: case PROF_V1_XAUTH_AM:
! 172: case PROF_V1_XAUTH_PSK_AM:
! 173: case PROF_V1_HYBRID_AM:
! 174: peer.aggressive = TRUE;
! 175: /* FALL */
! 176: case PROF_V1_PUB:
! 177: case PROF_V1_XAUTH:
! 178: case PROF_V1_XAUTH_PSK:
! 179: case PROF_V1_HYBRID:
! 180: ike.version = IKEV1;
! 181: break;
! 182: }
! 183:
! 184: ike.local_port = charon->socket->get_port(charon->socket, FALSE);
! 185: if (ike.local_port != IKEV2_UDP_PORT)
! 186: {
! 187: ike.remote_port = IKEV2_NATT_PORT;
! 188: }
! 189: ike_cfg = ike_cfg_create(&ike);
! 190: if (this->ike_proposals->get_count(this->ike_proposals))
! 191: {
! 192: while (this->ike_proposals->remove_first(this->ike_proposals,
! 193: (void**)&proposal) == SUCCESS)
! 194: {
! 195: ike_cfg->add_proposal(ike_cfg, proposal);
! 196: }
! 197: }
! 198: else
! 199: {
! 200: ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
! 201: ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
! 202: }
! 203: peer_cfg = peer_cfg_create("cmd", ike_cfg, &peer);
! 204:
! 205: return peer_cfg;
! 206: }
! 207:
! 208: /**
! 209: * Add a single auth cfg of given class to peer cfg
! 210: */
! 211: static void add_auth_cfg(private_cmd_connection_t *this, peer_cfg_t *peer_cfg,
! 212: bool local, auth_class_t class)
! 213: {
! 214: identification_t *id;
! 215: auth_cfg_t *auth;
! 216:
! 217: auth = auth_cfg_create();
! 218: auth->add(auth, AUTH_RULE_AUTH_CLASS, class);
! 219: if (local)
! 220: {
! 221: id = identification_create_from_string(this->identity);
! 222: if (this->xautheap)
! 223: {
! 224: switch (class)
! 225: {
! 226: case AUTH_CLASS_EAP:
! 227: auth->add(auth, AUTH_RULE_EAP_IDENTITY,
! 228: identification_create_from_string(this->xautheap));
! 229: break;
! 230: case AUTH_CLASS_XAUTH:
! 231: auth->add(auth, AUTH_RULE_XAUTH_IDENTITY,
! 232: identification_create_from_string(this->xautheap));
! 233: break;
! 234: default:
! 235: break;
! 236: }
! 237: }
! 238: }
! 239: else
! 240: {
! 241: if (this->server)
! 242: {
! 243: id = identification_create_from_string(this->server);
! 244: }
! 245: else
! 246: {
! 247: id = identification_create_from_string(this->host);
! 248: }
! 249: auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, TRUE);
! 250: }
! 251: auth->add(auth, AUTH_RULE_IDENTITY, id);
! 252: peer_cfg->add_auth_cfg(peer_cfg, auth, local);
! 253: }
! 254:
! 255: /**
! 256: * Attach authentication configs to peer config
! 257: */
! 258: static bool add_auth_cfgs(private_cmd_connection_t *this, peer_cfg_t *peer_cfg)
! 259: {
! 260: if (this->profile == PROF_UNDEF)
! 261: {
! 262: if (this->key_seen)
! 263: {
! 264: this->profile = PROF_V2_PUB;
! 265: }
! 266: else
! 267: {
! 268: this->profile = PROF_V2_EAP;
! 269: }
! 270: }
! 271: switch (this->profile)
! 272: {
! 273: case PROF_V2_PUB:
! 274: case PROF_V2_PUB_EAP:
! 275: case PROF_V1_PUB:
! 276: case PROF_V1_XAUTH:
! 277: case PROF_V1_PUB_AM:
! 278: case PROF_V1_XAUTH_AM:
! 279: if (!this->key_seen)
! 280: {
! 281: DBG1(DBG_CFG, "missing private key for profile %N",
! 282: profile_names, this->profile);
! 283: return FALSE;
! 284: }
! 285: break;
! 286: default:
! 287: break;
! 288: }
! 289:
! 290: switch (this->profile)
! 291: {
! 292: case PROF_V2_PUB:
! 293: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
! 294: add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY);
! 295: break;
! 296: case PROF_V2_EAP:
! 297: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_EAP);
! 298: add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY);
! 299: break;
! 300: case PROF_V2_PUB_EAP:
! 301: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
! 302: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_EAP);
! 303: add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY);
! 304: break;
! 305: case PROF_V1_PUB:
! 306: case PROF_V1_PUB_AM:
! 307: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
! 308: add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY);
! 309: break;
! 310: case PROF_V1_XAUTH:
! 311: case PROF_V1_XAUTH_AM:
! 312: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
! 313: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH);
! 314: add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY);
! 315: break;
! 316: case PROF_V1_XAUTH_PSK:
! 317: case PROF_V1_XAUTH_PSK_AM:
! 318: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PSK);
! 319: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH);
! 320: add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PSK);
! 321: break;
! 322: case PROF_V1_HYBRID:
! 323: case PROF_V1_HYBRID_AM:
! 324: add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH);
! 325: add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY);
! 326: break;
! 327: default:
! 328: return FALSE;
! 329: }
! 330: return TRUE;
! 331: }
! 332:
! 333: /**
! 334: * Attach child config to peer config
! 335: */
! 336: static child_cfg_t* create_child_cfg(private_cmd_connection_t *this,
! 337: peer_cfg_t *peer_cfg)
! 338: {
! 339: child_cfg_t *child_cfg;
! 340: traffic_selector_t *ts;
! 341: proposal_t *proposal;
! 342: bool has_v4 = FALSE, has_v6 = FALSE;
! 343: child_cfg_create_t child = {
! 344: .lifetime = {
! 345: .time = {
! 346: .life = 10800 /* 3h */,
! 347: .rekey = 10200 /* 2h50min */,
! 348: .jitter = 300 /* 5min */
! 349: }
! 350: },
! 351: .mode = MODE_TUNNEL,
! 352: };
! 353:
! 354: child_cfg = child_cfg_create("cmd", &child);
! 355: if (this->child_proposals->get_count(this->child_proposals))
! 356: {
! 357: while (this->child_proposals->remove_first(this->child_proposals,
! 358: (void**)&proposal) == SUCCESS)
! 359: {
! 360: child_cfg->add_proposal(child_cfg, proposal);
! 361: }
! 362: }
! 363: else
! 364: {
! 365: child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
! 366: child_cfg->add_proposal(child_cfg,
! 367: proposal_create_default_aead(PROTO_ESP));
! 368: }
! 369: while (this->local_ts->remove_first(this->local_ts, (void**)&ts) == SUCCESS)
! 370: {
! 371: child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
! 372: }
! 373: if (this->remote_ts->get_count(this->remote_ts) == 0)
! 374: {
! 375: /* add a 0.0.0.0/0 TS for remote side if none given */
! 376: ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
! 377: "0.0.0.0", 0, "255.255.255.255", 65535);
! 378: this->remote_ts->insert_last(this->remote_ts, ts);
! 379: has_v4 = TRUE;
! 380: }
! 381: while (this->remote_ts->remove_first(this->remote_ts,
! 382: (void**)&ts) == SUCCESS)
! 383: {
! 384: switch (ts->get_type(ts))
! 385: {
! 386: case TS_IPV4_ADDR_RANGE:
! 387: has_v4 = TRUE;
! 388: break;
! 389: case TS_IPV6_ADDR_RANGE:
! 390: has_v6 = TRUE;
! 391: break;
! 392: }
! 393: child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
! 394: }
! 395: if (has_v4)
! 396: {
! 397: peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
! 398: }
! 399: if (has_v6)
! 400: {
! 401: peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("::", 0));
! 402: }
! 403: peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg));
! 404:
! 405: return child_cfg;
! 406: }
! 407:
! 408: /**
! 409: * Initiate the configured connection
! 410: */
! 411: static job_requeue_t initiate(private_cmd_connection_t *this)
! 412: {
! 413: peer_cfg_t *peer_cfg;
! 414: child_cfg_t *child_cfg;
! 415: pid_t pid = this->pid;
! 416:
! 417: if (!this->host)
! 418: {
! 419: DBG1(DBG_CFG, "unable to initiate, missing --host option");
! 420: terminate(pid);
! 421: return JOB_REQUEUE_NONE;
! 422: }
! 423: if (!this->identity)
! 424: {
! 425: DBG1(DBG_CFG, "unable to initiate, missing --identity option");
! 426: terminate(pid);
! 427: return JOB_REQUEUE_NONE;
! 428: }
! 429:
! 430: peer_cfg = create_peer_cfg(this);
! 431:
! 432: if (!add_auth_cfgs(this, peer_cfg))
! 433: {
! 434: peer_cfg->destroy(peer_cfg);
! 435: terminate(pid);
! 436: return JOB_REQUEUE_NONE;
! 437: }
! 438:
! 439: child_cfg = create_child_cfg(this, peer_cfg);
! 440:
! 441: if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
! 442: controller_cb_empty, NULL, 0, FALSE) != SUCCESS)
! 443: {
! 444: terminate(pid);
! 445: }
! 446: return JOB_REQUEUE_NONE;
! 447: }
! 448:
! 449: /**
! 450: * Create a traffic selector from string, add to list
! 451: */
! 452: static void add_ts(private_cmd_connection_t *this,
! 453: linked_list_t *list, char *string)
! 454: {
! 455: traffic_selector_t *ts;
! 456:
! 457: ts = traffic_selector_create_from_cidr(string, 0, 0, 65535);
! 458: if (!ts)
! 459: {
! 460: DBG1(DBG_CFG, "invalid traffic selector: %s", string);
! 461: exit(1);
! 462: }
! 463: list->insert_last(list, ts);
! 464: }
! 465:
! 466: /**
! 467: * Parse profile name identifier
! 468: */
! 469: static void set_profile(private_cmd_connection_t *this, char *name)
! 470: {
! 471: profile_t profile;
! 472:
! 473: if (!enum_from_name(profile_names, name, &profile))
! 474: {
! 475: DBG1(DBG_CFG, "unknown connection profile: %s", name);
! 476: exit(1);
! 477: }
! 478: this->profile = profile;
! 479: }
! 480:
! 481: METHOD(cmd_connection_t, handle, bool,
! 482: private_cmd_connection_t *this, cmd_option_type_t opt, char *arg)
! 483: {
! 484: proposal_t *proposal;
! 485:
! 486: switch (opt)
! 487: {
! 488: case CMD_OPT_HOST:
! 489: this->host = arg;
! 490: break;
! 491: case CMD_OPT_REMOTE_IDENTITY:
! 492: this->server = arg;
! 493: break;
! 494: case CMD_OPT_IDENTITY:
! 495: this->identity = arg;
! 496: break;
! 497: case CMD_OPT_EAP_IDENTITY:
! 498: case CMD_OPT_XAUTH_USER:
! 499: this->xautheap = arg;
! 500: break;
! 501: case CMD_OPT_RSA:
! 502: case CMD_OPT_AGENT:
! 503: case CMD_OPT_PKCS12:
! 504: this->key_seen = TRUE;
! 505: break;
! 506: case CMD_OPT_LOCAL_TS:
! 507: add_ts(this, this->local_ts, arg);
! 508: break;
! 509: case CMD_OPT_REMOTE_TS:
! 510: add_ts(this, this->remote_ts, arg);
! 511: break;
! 512: case CMD_OPT_IKE_PROPOSAL:
! 513: proposal = proposal_create_from_string(PROTO_IKE, arg);
! 514: if (!proposal)
! 515: {
! 516: exit(1);
! 517: }
! 518: this->ike_proposals->insert_last(this->ike_proposals, proposal);
! 519: break;
! 520: case CMD_OPT_ESP_PROPOSAL:
! 521: proposal = proposal_create_from_string(PROTO_ESP, arg);
! 522: if (!proposal)
! 523: {
! 524: exit(1);
! 525: }
! 526: this->child_proposals->insert_last(this->child_proposals, proposal);
! 527: break;
! 528: case CMD_OPT_AH_PROPOSAL:
! 529: proposal = proposal_create_from_string(PROTO_AH, arg);
! 530: if (!proposal)
! 531: {
! 532: exit(1);
! 533: }
! 534: this->child_proposals->insert_last(this->child_proposals, proposal);
! 535: break;
! 536: case CMD_OPT_PROFILE:
! 537: set_profile(this, arg);
! 538: break;
! 539: default:
! 540: return FALSE;
! 541: }
! 542: return TRUE;
! 543: }
! 544:
! 545: METHOD(cmd_connection_t, destroy, void,
! 546: private_cmd_connection_t *this)
! 547: {
! 548: this->ike_proposals->destroy_offset(this->ike_proposals,
! 549: offsetof(proposal_t, destroy));
! 550: this->child_proposals->destroy_offset(this->child_proposals,
! 551: offsetof(proposal_t, destroy));
! 552: this->local_ts->destroy_offset(this->local_ts,
! 553: offsetof(traffic_selector_t, destroy));
! 554: this->remote_ts->destroy_offset(this->remote_ts,
! 555: offsetof(traffic_selector_t, destroy));
! 556: free(this);
! 557: }
! 558:
! 559: /**
! 560: * See header
! 561: */
! 562: cmd_connection_t *cmd_connection_create()
! 563: {
! 564: private_cmd_connection_t *this;
! 565:
! 566: INIT(this,
! 567: .public = {
! 568: .handle = _handle,
! 569: .destroy = _destroy,
! 570: },
! 571: .pid = getpid(),
! 572: .local_ts = linked_list_create(),
! 573: .remote_ts = linked_list_create(),
! 574: .ike_proposals = linked_list_create(),
! 575: .child_proposals = linked_list_create(),
! 576: .profile = PROF_UNDEF,
! 577: );
! 578:
! 579: /* always include the virtual IP in traffic selector list */
! 580: this->local_ts->insert_last(this->local_ts,
! 581: traffic_selector_create_dynamic(0, 0, 65535));
! 582:
! 583: /* queue job, gets initiated as soon as we are up and running */
! 584: lib->processor->queue_job(lib->processor,
! 585: (job_t*)callback_job_create_with_prio(
! 586: (callback_job_cb_t)initiate, this, NULL,
! 587: (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
! 588:
! 589: return &this->public;
! 590: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>