Annotation of embedaddon/strongswan/src/charon-cmd/cmd/cmd_connection.c, revision 1.1.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>