From 78d7a0f7e29af35902250cfd4f52bceee9a1608d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 15:07:15 +0100 Subject: [PATCH] charon-cmd: add a connection object and its initiation to charon-cmd --- src/charon-cmd/Makefile.am | 1 + src/charon-cmd/charon-cmd.c | 45 ++++-- src/charon-cmd/cmd/cmd_connection.c | 216 ++++++++++++++++++++++++++++ src/charon-cmd/cmd/cmd_connection.h | 55 +++++++ src/charon-cmd/cmd/cmd_options.c | 4 + src/charon-cmd/cmd/cmd_options.h | 2 + 6 files changed, 313 insertions(+), 10 deletions(-) create mode 100644 src/charon-cmd/cmd/cmd_connection.c create mode 100644 src/charon-cmd/cmd/cmd_connection.h diff --git a/src/charon-cmd/Makefile.am b/src/charon-cmd/Makefile.am index cd949e08f..ff360c18c 100644 --- a/src/charon-cmd/Makefile.am +++ b/src/charon-cmd/Makefile.am @@ -2,6 +2,7 @@ sbin_PROGRAMS = charon-cmd charon_cmd_SOURCES = \ cmd/cmd_options.h cmd/cmd_options.c \ + cmd/cmd_connection.h cmd/cmd_connection.c \ charon-cmd.c charon-cmd.o : $(top_builddir)/config.status diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index f93b619db..90cc8b6fa 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -33,12 +33,18 @@ #include #include "cmd/cmd_options.h" +#include "cmd/cmd_connection.h" /** * Loglevel configuration */ static level_t levels[DBG_MAX]; +/** + * Connection to initiate + */ +static cmd_connection_t *conn; + /** * hook in library for debugging messages */ @@ -61,18 +67,27 @@ static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) } } +/** + * Clean up connection definition atexit() + */ +static void cleanup_conn() +{ + DESTROY_IF(conn); +} + /** * Run the daemon and handle unix signals */ -static void run() +static int run() { sigset_t set; - /* handle SIGINT, SIGHUP ans SIGTERM in this handler */ + /* handle SIGINT, SIGHUP and SIGTERM in this handler */ sigemptyset(&set); sigaddset(&set, SIGINT); sigaddset(&set, SIGHUP); sigaddset(&set, SIGTERM); + sigaddset(&set, SIGUSR1); sigprocmask(SIG_BLOCK, &set, NULL); while (TRUE) @@ -84,7 +99,7 @@ static void run() if (error) { DBG1(DBG_DMN, "error %d while waiting for a signal", error); - return; + return 1; } switch (sig) { @@ -107,13 +122,18 @@ static void run() { DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down"); charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); - return; + return 0; } case SIGTERM: { DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down"); charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); - return; + return 0; + } + case SIGUSR1: + { /* an error occured */ + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return 1; } default: { @@ -212,7 +232,7 @@ static void handle_arguments(int argc, char *argv[]) while (TRUE) { struct option long_opts[CMD_OPT_COUNT + 1] = {}; - int i; + int i, opt; for (i = 0; i < CMD_OPT_COUNT; i++) { @@ -221,7 +241,8 @@ static void handle_arguments(int argc, char *argv[]) long_opts[i].has_arg = cmd_options[i].has_arg; } - switch (getopt_long(argc, argv, "", long_opts, NULL)) + opt = getopt_long(argc, argv, "", long_opts, NULL); + switch (opt) { case EOF: break; @@ -232,6 +253,10 @@ static void handle_arguments(int argc, char *argv[]) printf("%s, strongSwan %s\n", "charon-cmd", VERSION); exit(0); default: + if (conn->handle(conn, opt, optarg)) + { + continue; + } usage(stderr, NULL, argv[0]); exit(1); } @@ -275,6 +300,8 @@ int main(int argc, char *argv[]) { levels[group] = LEVEL_CTRL; } + conn = cmd_connection_create(); + atexit(cleanup_conn); handle_arguments(argc, argv); @@ -320,7 +347,5 @@ int main(int argc, char *argv[]) /* start daemon with thread-pool */ charon->start(charon); /* wait for signal */ - run(); - - return 0; + return run(); } diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c new file mode 100644 index 000000000..566b2544b --- /dev/null +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "cmd_connection.h" + +#include +#include + +#include +#include +#include + +typedef struct private_cmd_connection_t private_cmd_connection_t; + +/** + * Private data of an cmd_connection_t object. + */ +struct private_cmd_connection_t { + + /** + * Public cmd_connection_t interface. + */ + cmd_connection_t public; + + /** + * Process ID to terminate on failure + */ + pid_t pid; + + /** + * Hostname to connect to + */ + char *host; + + /** + * Local identity + */ + char *identity; +}; + +/** + * Shut down application + */ +static void terminate(private_cmd_connection_t *this) +{ + kill(this->pid, SIGUSR1); +} + +/** + * Create peer config with associated ike config + */ +static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) +{ + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + + ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, + charon->socket->get_port(charon->socket, FALSE), + this->host, FALSE, IKEV2_UDP_PORT, + FRAGMENTATION_NO, 0); + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + peer_cfg = peer_cfg_create("cmd", ike_cfg, + CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ + 36000, 0, /* rekey 10h, reauth none */ + 600, 600, /* jitter, over 10min */ + TRUE, FALSE, /* mobike, aggressive */ + 30, 0, /* DPD delay, timeout */ + FALSE, NULL, NULL); /* mediation */ + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); + + return peer_cfg; +} + +/** + * Attach authentication configs to peer config + */ +static void add_auth_cfgs(private_cmd_connection_t *this, peer_cfg_t *peer_cfg) +{ + auth_cfg_t *auth; + + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_string(this->identity)); + peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); + + auth = auth_cfg_create(); + + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_string(this->host)); + peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); +} + +/** + * Attach child config to peer config + */ +static child_cfg_t* create_child_cfg(private_cmd_connection_t *this) +{ + child_cfg_t *child_cfg; + traffic_selector_t *ts; + lifetime_cfg_t lifetime = { + .time = { + .life = 10800 /* 3h */, + .rekey = 10200 /* 2h50min */, + .jitter = 300 /* 5min */ + } + }; + + child_cfg = child_cfg_create("cmd", &lifetime, + NULL, FALSE, MODE_TUNNEL, /* updown, hostaccess */ + ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, + 0, 0, NULL, NULL, 0); + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + ts = traffic_selector_create_dynamic(0, 0, 65535); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts); + ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, + "0.0.0.0", 0, "255.255.255.255", 65535); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts); + + return child_cfg; +} + +/** + * Initiate the configured connection + */ +static job_requeue_t initiate(private_cmd_connection_t *this) +{ + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + + if (!this->host) + { + DBG1(DBG_CFG, "unable to initiate, missing --host option"); + terminate(this); + return JOB_REQUEUE_NONE; + } + if (!this->identity) + { + DBG1(DBG_CFG, "unable to initiate, missing --identity option"); + terminate(this); + return JOB_REQUEUE_NONE; + } + + peer_cfg = create_peer_cfg(this); + + add_auth_cfgs(this, peer_cfg); + + child_cfg = create_child_cfg(this); + peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg)); + + if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg, + controller_cb_empty, NULL, 0) != SUCCESS) + { + terminate(this); + } + return JOB_REQUEUE_NONE; +} + +METHOD(cmd_connection_t, handle, bool, + private_cmd_connection_t *this, cmd_option_type_t opt, char *arg) +{ + switch (opt) + { + case CMD_OPT_HOST: + this->host = arg; + break; + case CMD_OPT_IDENTITY: + this->identity = arg; + break; + default: + return FALSE; + } + return TRUE; +} + +METHOD(cmd_connection_t, destroy, void, + private_cmd_connection_t *this) +{ + free(this); +} + +/** + * See header + */ +cmd_connection_t *cmd_connection_create() +{ + private_cmd_connection_t *this; + + INIT(this, + .public = { + .handle = _handle, + .destroy = _destroy, + }, + .pid = getpid(), + ); + + /* queue job, gets initiated as soon as we are up and running */ + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio( + (callback_job_cb_t)initiate, this, NULL, + (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); + + return &this->public; +} diff --git a/src/charon-cmd/cmd/cmd_connection.h b/src/charon-cmd/cmd/cmd_connection.h new file mode 100644 index 000000000..0f167bfdc --- /dev/null +++ b/src/charon-cmd/cmd/cmd_connection.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup cmd_connection cmd_connection + * @{ @ingroup cmd + */ + +#ifndef CMD_CONNECTION_H_ +#define CMD_CONNECTION_H_ + +#include + +#include "cmd_options.h" + +typedef struct cmd_connection_t cmd_connection_t; + +/** + * Connection definition to construct and initiate. + */ +struct cmd_connection_t { + + /** + * Handle a command line option. + * + * @param opt option to handle + * @param arg option argument + * @return TRUE if option handled + */ + bool (*handle)(cmd_connection_t *this, cmd_option_type_t opt, char *arg); + + /** + * Destroy a cmd_connection_t. + */ + void (*destroy)(cmd_connection_t *this); +}; + +/** + * Create a cmd_connection instance. + */ +cmd_connection_t *cmd_connection_create(); + +#endif /** CMD_CONNECTION_H_ @}*/ diff --git a/src/charon-cmd/cmd/cmd_options.c b/src/charon-cmd/cmd/cmd_options.c index 997cd3431..899cdd119 100644 --- a/src/charon-cmd/cmd/cmd_options.c +++ b/src/charon-cmd/cmd/cmd_options.c @@ -25,4 +25,8 @@ cmd_option_t cmd_options[CMD_OPT_COUNT] = { "print this usage information and exit" }, { CMD_OPT_VERSION, "version", no_argument, "", "show version information and exit" }, + { CMD_OPT_HOST, "host", required_argument, "hostname", + "DNS name or address to connect to" }, + { CMD_OPT_IDENTITY, "identity", required_argument, "identity", + "identity the client uses for the IKE exchange" }, }; diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h index d453a53eb..81fb54fe1 100644 --- a/src/charon-cmd/cmd/cmd_options.h +++ b/src/charon-cmd/cmd/cmd_options.h @@ -30,6 +30,8 @@ typedef enum cmd_option_type_t cmd_option_type_t; enum cmd_option_type_t { CMD_OPT_HELP, CMD_OPT_VERSION, + CMD_OPT_HOST, + CMD_OPT_IDENTITY, CMD_OPT_COUNT };