From 78fe2cda0572433e40889bcd7d64dd22707bfdd0 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 16 Mar 2012 08:08:16 +0100 Subject: Move command line parsing to a new file --- src/CMakeLists.txt | 2 +- src/configure.c | 294 ++++++++++++++++++++++++++ src/fastd.c | 245 +-------------------- src/fastd.h | 4 +- src/method_ec25519_fhmqvc_xsalsa20_poly1305.c | 11 + src/method_null.c | 5 + 6 files changed, 315 insertions(+), 246 deletions(-) create mode 100644 src/configure.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7315aa0..223c62a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,5 +10,5 @@ endif(WITH_METHOD_ECFXP) include_directories(${FASTD_INCLUDES}) -add_executable(fastd fastd.c handshake.c peer.c printf.c queue.c task.c ${METHODS}) +add_executable(fastd fastd.c configure.c handshake.c peer.c printf.c queue.c task.c ${METHODS}) target_link_libraries(fastd rt ${FASTD_LIBS}) diff --git a/src/configure.c b/src/configure.c new file mode 100644 index 0000000..7473696 --- /dev/null +++ b/src/configure.c @@ -0,0 +1,294 @@ +/* + Copyright (c) 2012, Matthias Schiffer + Partly based on QuickTun Copyright (c) 2010, Ivo Smits . + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "fastd.h" +#include "peer.h" + +#include + +#include +#include + + +extern fastd_method fastd_method_null; + +#ifdef WITH_METHOD_ECFXP +extern fastd_method fastd_method_ec25519_fhmqvc_xsalsa20_poly1305; +#endif + + +static void default_config(fastd_config *conf) { + conf->loglevel = LOG_DEBUG; + + conf->peer_stale_time = 300; + conf->peer_stale_time_temp = 30; + conf->eth_addr_stale_time = 300; + + conf->ifname = NULL; + + memset(&conf->bind_addr_in, 0, sizeof(struct sockaddr_in)); + conf->bind_addr_in.sin_family = AF_UNSPEC; + conf->bind_addr_in.sin_port = htons(1337); + conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); + + memset(&conf->bind_addr_in6, 0, sizeof(struct sockaddr_in6)); + conf->bind_addr_in6.sin6_family = AF_UNSPEC; + conf->bind_addr_in6.sin6_port = htons(1337); + conf->bind_addr_in6.sin6_addr = in6addr_any; + + conf->mtu = 1500; + conf->protocol = PROTOCOL_ETHERNET; + conf->method = &fastd_method_null; + conf->peers = NULL; +} + +static bool config_match(const char *opt, ...) { + va_list ap; + bool match = false; + const char *str; + + va_start(ap, opt); + + while((str = va_arg(ap, const char*)) != NULL) { + if (strcmp(opt, str) == 0) { + match = true; + break; + } + } + + va_end(ap); + + return match; +} + +#define IF_OPTION(args...) if(config_match(argv[i], args, NULL) && (++i)) +#define IF_OPTION_ARG(args...) if(config_match(argv[i], args, NULL) && ({ \ + arg = argv[i+1]; \ + i+=2; \ + if (i > argc) \ + exit_error(ctx, "config error: option `%s' needs an argument", argv[i-2]); \ + true; \ + })) +#define IGNORE_OPTION (i++) + +void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *const argv[]) { + default_config(conf); + + fastd_peer_config **current_peer = &conf->peers; + + int i = 1; + const char *arg; + long l; + char *charptr; + char *endptr; + char *addrstr; + + bool v4_peers = false, v6_peers = false; + + + conf->n_floating = 0; + + + while (i < argc) { + IF_OPTION_ARG("-i", "--interface") { + conf->ifname = arg; + continue; + } + + IF_OPTION_ARG("-b", "--bind") { + if (arg[0] == '[') { + charptr = strchr(arg, ']'); + if (!charptr || (charptr[1] != ':' && charptr[1] != '\0')) + exit_error(ctx, "invalid bind address `%s'", arg); + + addrstr = strndup(arg+1, charptr-arg-1); + + if (charptr[1] == ':') + charptr++; + else + charptr = NULL; + } + else { + charptr = strchr(arg, ':'); + if (charptr) { + addrstr = strndup(arg, charptr-arg); + } + else { + addrstr = strdup(arg); + } + } + + if (charptr) { + l = strtol(charptr+1, &endptr, 10); + if (*endptr || l > 65535) + exit_error(ctx, "invalid bind port `%s'", charptr+1); + } + + if (strcmp(addrstr, "any") == 0) { + conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); + conf->bind_addr_in.sin_port = htons(l); + + conf->bind_addr_in6.sin6_addr = in6addr_any; + conf->bind_addr_in6.sin6_port = htons(l); + } + else if (arg[0] == '[') { + conf->bind_addr_in6.sin6_family = AF_INET6; + if (inet_pton(AF_INET6, addrstr, &conf->bind_addr_in6.sin6_addr) != 1) + exit_error(ctx, "invalid bind address `%s'", addrstr); + conf->bind_addr_in6.sin6_port = htons(l); + } + else { + conf->bind_addr_in.sin_family = AF_INET; + if (inet_pton(AF_INET, addrstr, &conf->bind_addr_in.sin_addr) != 1) + exit_error(ctx, "invalid bind address `%s'", addrstr); + conf->bind_addr_in.sin_port = htons(l); + } + + free(addrstr); + + continue; + } + + IF_OPTION_ARG("-M", "--mtu") { + conf->mtu = strtol(arg, &endptr, 10); + if (*endptr || conf->mtu < 576) + exit_error(ctx, "invalid mtu `%s'", arg); + continue; + } + + IF_OPTION_ARG("-P", "--protocol") { + if (!strcmp(arg, "ethernet")) + conf->protocol = PROTOCOL_ETHERNET; + else if (!strcmp(arg, "ip")) + conf->protocol = PROTOCOL_IP; + else + exit_error(ctx, "invalid protocol `%s'", arg); + continue; + } + + + IF_OPTION_ARG("-m", "--method") { + if (!strcmp(arg, "null")) + conf->method = &fastd_method_null; +#ifdef WITH_METHOD_ECFXP + if (!strcmp(arg, "ecfxp")) + conf->method = &fastd_method_ec25519_fhmqvc_xsalsa20_poly1305; +#endif + else + exit_error(ctx, "invalid method `%s'", arg); + continue; + } + + IF_OPTION_ARG("-p", "--peer") { + *current_peer = malloc(sizeof(fastd_peer_config)); + (*current_peer)->next = NULL; + + memset(&(*current_peer)->address, 0, sizeof(fastd_peer_address)); + if (strcmp(arg, "float") == 0) { + (*current_peer)->address.sa.sa_family = AF_UNSPEC; + conf->n_floating++; + continue; + } + + if (arg[0] == '[') { + charptr = strchr(arg, ']'); + if (!charptr || (charptr[1] != ':' && charptr[1] != '\0')) + exit_error(ctx, "invalid peer address `%s'", arg); + + addrstr = strndup(arg+1, charptr-arg-1); + + if (charptr[1] == ':') + charptr++; + else + charptr = NULL; + } + else { + charptr = strchr(arg, ':'); + if (charptr) + addrstr = strndup(arg, charptr-arg); + else + addrstr = strdup(arg); + } + + if (charptr) { + l = strtol(charptr+1, &endptr, 10); + if (*endptr || l > 65535) + exit_error(ctx, "invalid peer port `%s'", charptr+1); + } + else { + l = 1337; /* default port */ + } + + if (arg[0] == '[') { + v6_peers = true; + (*current_peer)->address.in6.sin6_family = AF_INET6; + if (inet_pton(AF_INET6, addrstr, &(*current_peer)->address.in6.sin6_addr) != 1) + exit_error(ctx, "invalid peer address `%s'", addrstr); + (*current_peer)->address.in6.sin6_port = htons(l); + } + else { + v4_peers = true; + (*current_peer)->address.in.sin_family = AF_INET; + if (inet_pton(AF_INET, addrstr, &(*current_peer)->address.in.sin_addr) != 1) + exit_error(ctx, "invalid peer address `%s'", addrstr); + (*current_peer)->address.in.sin_port = htons(l); + } + + free(addrstr); + + current_peer = &(*current_peer)->next; + + continue; + } + + exit_error(ctx, "config error: unknown option `%s'", argv[i]); + } + + if (conf->n_floating && conf->bind_addr_in.sin_family == AF_UNSPEC + && conf->bind_addr_in6.sin6_family == AF_UNSPEC) { + conf->bind_addr_in.sin_family = AF_INET; + conf->bind_addr_in6.sin6_family = AF_INET6; + } + else if (v4_peers) { + conf->bind_addr_in.sin_family = AF_INET; + } + else if (v6_peers) { + conf->bind_addr_in6.sin6_family = AF_INET6; + } + + bool ok = true; + if (conf->protocol == PROTOCOL_IP && (!conf->peers || conf->peers->next)) { + pr_error(ctx, "for protocol `ip' exactly one peer must be configured"); + ok = false; + } + + if (ok) + ok = conf->method->check_config(ctx, conf); + + if (!ok) + exit_error(ctx, "config error"); +} diff --git a/src/fastd.c b/src/fastd.c index 496df97..cae7c64 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -30,28 +30,16 @@ #include "peer.h" #include "task.h" -#include - -#include #include -#include #include #include #include -#include #include #include #include #include -extern fastd_method fastd_method_null; - -#ifdef WITH_METHOD_ECFXP -extern fastd_method fastd_method_ec25519_fhmqvc_xsalsa20_poly1305; -#endif - - static void init_tuntap(fastd_context *ctx) { struct ifreq ifr; @@ -126,237 +114,6 @@ static void init_socket(fastd_context *ctx) { } } -static void default_config(fastd_config *conf) { - conf->loglevel = LOG_DEBUG; - - conf->peer_stale_time = 300; - conf->peer_stale_time_temp = 30; - conf->eth_addr_stale_time = 300; - - conf->ifname = NULL; - - memset(&conf->bind_addr_in, 0, sizeof(struct sockaddr_in)); - conf->bind_addr_in.sin_family = AF_UNSPEC; - conf->bind_addr_in.sin_port = htons(1337); - conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); - - memset(&conf->bind_addr_in6, 0, sizeof(struct sockaddr_in6)); - conf->bind_addr_in6.sin6_family = AF_UNSPEC; - conf->bind_addr_in6.sin6_port = htons(1337); - conf->bind_addr_in6.sin6_addr = in6addr_any; - - conf->mtu = 1500; - conf->protocol = PROTOCOL_ETHERNET; - conf->method = &fastd_method_null; - conf->peers = NULL; -} - -static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *argv[]) { - default_config(conf); - - fastd_peer_config **current_peer = &conf->peers; - - static const struct option long_options[] = { - {"interface", required_argument, 0, 'i'}, - {"bind", required_argument, 0, 'b'}, - {"mtu", required_argument, 0, 'M'}, - {"protocol", required_argument, 0, 'P'}, - {"method", required_argument, 0, 'm'}, - {"peer", required_argument, 0, 'p'}, - {0, 0, 0, 0} - }; - - int c; - int option_index = 0; - long l; - char *charptr; - char *endptr; - char *addrstr; - - bool v4_peers = false, v6_peers = false; - - - conf->n_floating = 0; - - while ((c = getopt_long (argc, argv, "i:b:M:P:m:p:", long_options, &option_index)) != -1) { - switch(c) { - case 'i': - conf->ifname = optarg; - break; - - case 'b': - if (optarg[0] == '[') { - charptr = strchr(optarg, ']'); - if (!charptr || (charptr[1] != ':' && charptr[1] != '\0')) - exit_error(ctx, "invalid bind address `%s'", optarg); - - addrstr = strndup(optarg+1, charptr-optarg-1); - - if (charptr[1] == ':') - charptr++; - else - charptr = NULL; - } - else { - charptr = strchr(optarg, ':'); - if (charptr) { - addrstr = strndup(optarg, charptr-optarg); - } - else { - addrstr = strdup(optarg); - } - } - - if (charptr) { - l = strtol(charptr+1, &endptr, 10); - if (*endptr || l > 65535) - exit_error(ctx, "invalid bind port `%s'", charptr+1); - } - - if (strcmp(addrstr, "any") == 0) { - conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); - conf->bind_addr_in.sin_port = htons(l); - - conf->bind_addr_in6.sin6_addr = in6addr_any; - conf->bind_addr_in6.sin6_port = htons(l); - } - else if (optarg[0] == '[') { - conf->bind_addr_in6.sin6_family = AF_INET6; - if (inet_pton(AF_INET6, addrstr, &conf->bind_addr_in6.sin6_addr) != 1) - exit_error(ctx, "invalid bind address `%s'", addrstr); - conf->bind_addr_in6.sin6_port = htons(l); - } - else { - conf->bind_addr_in.sin_family = AF_INET; - if (inet_pton(AF_INET, addrstr, &conf->bind_addr_in.sin_addr) != 1) - exit_error(ctx, "invalid bind address `%s'", addrstr); - conf->bind_addr_in.sin_port = htons(l); - } - - free(addrstr); - - break; - - case 'M': - conf->mtu = strtol(optarg, &endptr, 10); - if (*endptr || conf->mtu < 576) - exit_error(ctx, "invalid mtu `%s'", optarg); - break; - - case 'P': - if (!strcmp(optarg, "ethernet")) - conf->protocol = PROTOCOL_ETHERNET; - else if (!strcmp(optarg, "ip")) - conf->protocol = PROTOCOL_IP; - else - exit_error(ctx, "invalid protocol `%s'", optarg); - break; - - case 'm': - if (!strcmp(optarg, "null")) - conf->method = &fastd_method_null; -#ifdef WITH_METHOD_ECFXP - if (!strcmp(optarg, "ecfxp")) - conf->method = &fastd_method_ec25519_fhmqvc_xsalsa20_poly1305; -#endif - else - exit_error(ctx, "invalid method `%s'", optarg); - break; - - case 'p': - *current_peer = malloc(sizeof(fastd_peer_config)); - (*current_peer)->next = NULL; - - memset(&(*current_peer)->address, 0, sizeof(fastd_peer_address)); - if (strcmp(optarg, "float") == 0) { - (*current_peer)->address.sa.sa_family = AF_UNSPEC; - conf->n_floating++; - continue; - } - - if (optarg[0] == '[') { - charptr = strchr(optarg, ']'); - if (!charptr || (charptr[1] != ':' && charptr[1] != '\0')) - exit_error(ctx, "invalid peer address `%s'", optarg); - - addrstr = strndup(optarg+1, charptr-optarg-1); - - if (charptr[1] == ':') - charptr++; - else - charptr = NULL; - } - else { - charptr = strchr(optarg, ':'); - if (charptr) - addrstr = strndup(optarg, charptr-optarg); - else - addrstr = strdup(optarg); - } - - if (charptr) { - l = strtol(charptr+1, &endptr, 10); - if (*endptr || l > 65535) - exit_error(ctx, "invalid peer port `%s'", charptr+1); - } - else { - l = 1337; /* default port */ - } - - if (optarg[0] == '[') { - v6_peers = true; - (*current_peer)->address.in6.sin6_family = AF_INET6; - if (inet_pton(AF_INET6, addrstr, &(*current_peer)->address.in6.sin6_addr) != 1) - exit_error(ctx, "invalid peer address `%s'", addrstr); - (*current_peer)->address.in6.sin6_port = htons(l); - } - else { - v4_peers = true; - (*current_peer)->address.in.sin_family = AF_INET; - if (inet_pton(AF_INET, addrstr, &(*current_peer)->address.in.sin_addr) != 1) - exit_error(ctx, "invalid peer address `%s'", addrstr); - (*current_peer)->address.in.sin_port = htons(l); - } - - free(addrstr); - - current_peer = &(*current_peer)->next; - - break; - - case '?': - exit(1); - - default: - abort(); - } - } - - if (conf->n_floating && conf->bind_addr_in.sin_family == AF_UNSPEC - && conf->bind_addr_in6.sin6_family == AF_UNSPEC) { - conf->bind_addr_in.sin_family = AF_INET; - conf->bind_addr_in6.sin6_family = AF_INET6; - } - else if (v4_peers) { - conf->bind_addr_in.sin_family = AF_INET; - } - else if (v6_peers) { - conf->bind_addr_in6.sin6_family = AF_INET6; - } - - bool ok = true; - if (conf->protocol == PROTOCOL_IP && (!conf->peers || conf->peers->next)) { - pr_error(ctx, "for protocol `ip' exactly one peer must be configured"); - ok = false; - } - - if (ok) - ok = conf->method->check_config(ctx, conf); - - if (!ok) - exit_error(ctx, "config error"); -} - static void init_peers(fastd_context *ctx) { fastd_peer_config *peer_conf; for (peer_conf = ctx->conf->peers; peer_conf; peer_conf = peer_conf->next) @@ -631,7 +388,7 @@ int main(int argc, char *argv[]) { memset(&ctx, 0, sizeof(ctx)); fastd_config conf; - configure(&ctx, &conf, argc, argv); + fastd_configure(&ctx, &conf, argc, argv); ctx.conf = &conf; update_time(&ctx); diff --git a/src/fastd.h b/src/fastd.h index 834fa39..c42baa3 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -59,6 +59,7 @@ struct _fastd_eth_addr { struct _fastd_method { const char *name; + bool (*handle_config)(fastd_context *ctx, const fastd_config *conf, const char *option); bool (*check_config)(fastd_context *ctx, const fastd_config *conf); size_t (*max_packet_size)(fastd_context *ctx); @@ -80,7 +81,7 @@ struct _fastd_config { unsigned peer_stale_time_temp; unsigned eth_addr_stale_time; - char *ifname; + const char *ifname; struct sockaddr_in bind_addr_in; struct sockaddr_in6 bind_addr_in6; @@ -113,6 +114,7 @@ struct _fastd_context { void fastd_printf(const fastd_context *ctx, const char *format, ...); +void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *const argv[]); #define pr_log(ctx, level, prefix, args...) if ((ctx)->conf == NULL || (level) <= (ctx)->conf->loglevel) \ do { fputs(prefix, stderr); fastd_printf(ctx, args); fputs("\n", stderr); } while(0) diff --git a/src/method_ec25519_fhmqvc_xsalsa20_poly1305.c b/src/method_ec25519_fhmqvc_xsalsa20_poly1305.c index 2a01ccd..b57531f 100644 --- a/src/method_ec25519_fhmqvc_xsalsa20_poly1305.c +++ b/src/method_ec25519_fhmqvc_xsalsa20_poly1305.c @@ -36,13 +36,23 @@ #include +typedef struct _method_config { + ecc_secret_key_256 secret_key; +} method_config; + typedef struct _method_peer_config { + ecc_public_key_256 public_key; } method_peer_config; typedef struct _method_peer_state { } method_peer_state; +static bool method_handle_config(fastd_context *ctx, const fastd_config *conf, const char *option) { + printf("Unknown option: %s\n", option); + return false; +} + static bool method_check_config(fastd_context *ctx, const fastd_config *conf) { return true; } @@ -103,6 +113,7 @@ static void method_free_peer_private(fastd_context *ctx, fastd_peer *peer) { const fastd_method fastd_method_ec25519_fhmqvc_xsalsa20_poly1305 = { .name = "ec25519-fhmqvc-xsalsa20-poly1305", + .handle_config = method_handle_config, .check_config = method_check_config, .max_packet_size = method_max_packet_size, diff --git a/src/method_null.c b/src/method_null.c index f5a0d74..70c5a09 100644 --- a/src/method_null.c +++ b/src/method_null.c @@ -34,6 +34,10 @@ #include +static bool method_handle_config(fastd_context *ctx, const fastd_config *conf, const char *option) { + return false; +} + static bool method_check_config(fastd_context *ctx, const fastd_config *conf) { if (conf->n_floating > 1) { pr_error(ctx, "with method `null' use can't define more than one floating peer"); @@ -125,6 +129,7 @@ static void method_free_peer_private(fastd_context *ctx, fastd_peer *peer) { const fastd_method fastd_method_null = { .name = "null", + .handle_config = method_handle_config, .check_config = method_check_config, .max_packet_size = method_max_packet_size, -- cgit v1.2.3