From 4ffc28ecd6d914f9c1e5aaf5d5921ee4827bb289 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 24 Mar 2012 20:55:27 +0100 Subject: Partial implementation of a config files parser --- CMakeLists.txt | 3 + FindFLEX.cmake | 120 ++++++++++++++++++++ src/CMakeLists.txt | 18 ++- src/config.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/config.l | 57 ++++++++++ src/config.y | 106 ++++++++++++++++++ src/configure.c | 294 ------------------------------------------------- src/fastd.c | 12 +- src/fastd.h | 10 +- src/handshake.c | 12 +- src/packet.h | 2 +- src/peer.c | 12 +- src/types.h | 8 +- 13 files changed, 646 insertions(+), 324 deletions(-) create mode 100644 FindFLEX.cmake create mode 100644 src/config.c create mode 100644 src/config.l create mode 100644 src/config.y delete mode 100644 src/configure.c diff --git a/CMakeLists.txt b/CMakeLists.txt index da8027e..ed04b15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,9 @@ project(FASTD C) set(CMAKE_MODULE_PATH ${FASTD_SOURCE_DIR}) +find_package(BISON REQUIRED) +find_package(FLEX REQUIRED) + find_package(UECC) find_package(NaCl) diff --git a/FindFLEX.cmake b/FindFLEX.cmake new file mode 100644 index 0000000..fe83369 --- /dev/null +++ b/FindFLEX.cmake @@ -0,0 +1,120 @@ +#============================================================================= +# Copyright 2009 Kitware, Inc. +# Copyright 2006 Tristan Carel +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * 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. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# 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. +# +# ------------------------------------------------------------------------------ +# +# The above copyright and license notice applies to distributions of +# CMake in source and binary form. Some source files contain additional +# notices of original copyright by their contributors; see each source +# for details. Third-party software packages supplied with CMake under +# compatible licenses provide their own copyright notices documented in +# corresponding subdirectories. +#============================================================================= + +FIND_PROGRAM(FLEX_EXECUTABLE flex DOC "path to the flex executable") +MARK_AS_ADVANCED(FLEX_EXECUTABLE) + +FIND_LIBRARY(FL_LIBRARY NAMES fl + DOC "Path to the fl library") + +FIND_PATH(FLEX_INCLUDE_DIR FlexLexer.h + DOC "Path to the flex headers") + +MARK_AS_ADVANCED(FL_LIBRARY FLEX_INCLUDE_DIR) + +SET(FLEX_INCLUDE_DIRS ${FLEX_INCLUDE_DIR}) +SET(FLEX_LIBRARIES ${FL_LIBRARY}) + +IF(FLEX_EXECUTABLE) + + EXECUTE_PROCESS(COMMAND ${FLEX_EXECUTABLE} --version + OUTPUT_VARIABLE FLEX_version_output + ERROR_VARIABLE FLEX_version_error + RESULT_VARIABLE FLEX_version_result + OUTPUT_STRIP_TRAILING_WHITESPACE) + IF(NOT ${FLEX_version_result} EQUAL 0) + IF(FLEX_FIND_REQUIRED) + MESSAGE(SEND_ERROR "Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}") + ELSE() + MESSAGE("Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}\nFLEX_VERSION will not be available") + ENDIF() + ELSE() + STRING(REGEX REPLACE "^flex (.*)$" "\\1" + FLEX_VERSION "${FLEX_version_output}") + ENDIF() + + #============================================================ + # FLEX_TARGET (public macro) + #============================================================ + # + MACRO(FLEX_TARGET Name Input Output) + SET(FLEX_TARGET_usage "FLEX_TARGET( [COMPILE_FLAGS ]") + IF(${ARGC} GREATER 3) + IF(${ARGC} EQUAL 5) + IF("${ARGV3}" STREQUAL "COMPILE_FLAGS") + SET(FLEX_EXECUTABLE_opts "${ARGV4}") + SEPARATE_ARGUMENTS(FLEX_EXECUTABLE_opts) + ELSE() + MESSAGE(SEND_ERROR ${FLEX_TARGET_usage}) + ENDIF() + ELSE() + MESSAGE(SEND_ERROR ${FLEX_TARGET_usage}) + ENDIF() + ENDIF() + + STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\2" _fileext "${Output}") + STRING(REPLACE "c" "h" _fileext ${_fileext}) + STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\1${_fileext}" + OutputHeader "${Output}") + + ADD_CUSTOM_COMMAND(OUTPUT ${Output} ${OutputHeader} + COMMAND ${FLEX_EXECUTABLE} + ARGS ${FLEX_EXECUTABLE_opts} -o${Output} --header-file=${OutputHeader} ${Input} + DEPENDS ${Input} + COMMENT "[FLEX][${Name}] Building scanner with flex ${FLEX_VERSION}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + + SET(FLEX_${Name}_DEFINED TRUE) + SET(FLEX_${Name}_OUTPUTS ${Output} ${OutputHeader}) + SET(FLEX_${Name}_OUTPUT_HEADER ${OutputHeader}) + SET(FLEX_${Name}_INPUT ${Input}) + SET(FLEX_${Name}_COMPILE_FLAGS ${FLEX_EXECUTABLE_opts}) + ENDMACRO(FLEX_TARGET) + #============================================================ + + +ENDIF(FLEX_EXECUTABLE) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLEX REQUIRED_VARS FLEX_EXECUTABLE + VERSION_VAR FLEX_VERSION) + +# FindFLEX.cmake ends here diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 223c62a..1da7d13 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ set(METHODS method_null.c) -set(FASTD_INCLUDES ${FASTD_BINARY_DIR}) +set(FASTD_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${FASTD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) set(FASTD_LIBS "") if(WITH_METHOD_ECFXP) @@ -10,5 +10,19 @@ endif(WITH_METHOD_ECFXP) include_directories(${FASTD_INCLUDES}) -add_executable(fastd fastd.c configure.c handshake.c peer.c printf.c queue.c task.c ${METHODS}) +FLEX_TARGET(fastd_config_lex config.l ${CMAKE_CURRENT_BINARY_DIR}/config.ll.c) +BISON_TARGET(fastd_config_parse config.y ${CMAKE_CURRENT_BINARY_DIR}/config.yy.c) + +add_executable(fastd + fastd.c + config.c + handshake.c + peer.c + printf.c + queue.c + task.c + ${FLEX_fastd_config_lex_OUTPUTS} + ${BISON_fastd_config_parse_OUTPUTS} + ${METHODS} +) target_link_libraries(fastd rt ${FASTD_LIBS}) diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..18fe120 --- /dev/null +++ b/src/config.c @@ -0,0 +1,316 @@ +/* + 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 + +#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 = 0; + 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 = 0; + conf->bind_addr_in6.sin6_addr = in6addr_any; + + conf->mtu = 1500; + conf->mode = MODE_TAP; + 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; +} + +static void fastd_read_config(fastd_context *ctx, fastd_config *conf, const char *filename) { + yyscan_t scanner; + FILE *file; + + file = fopen(filename, "r"); + fastd_config_lex_init(&scanner); + + fastd_config_set_in(file, scanner); + + fastd_config_parse(ctx, conf, scanner); + + fastd_config_lex_destroy(scanner); + fclose(file); +} + +#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("-c", "--config") { + fastd_read_config(ctx, conf, arg); + continue; + } + + 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("-m", "--mode") { + if (!strcmp(arg, "tap")) + conf->mode = MODE_TAP; + else if (!strcmp(arg, "tun")) + conf->mode = MODE_TUN; + else + exit_error(ctx, "invalid mode `%s'", arg); + continue; + } + + + IF_OPTION_ARG("-P", "--protocol") { + 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 protocol `%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->mode == MODE_TUN && (!conf->peers || conf->peers->next)) { + pr_error(ctx, "for tun mode 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/config.l b/src/config.l new file mode 100644 index 0000000..e9dd235 --- /dev/null +++ b/src/config.l @@ -0,0 +1,57 @@ +%option prefix="fastd_config_" +%option noyywrap +%option bison-bridge +%option reentrant + +%top { + #include + #include + #define YY_DECL int fastd_config_lex(YYSTYPE *yylval_param, fastd_context *ctx, void *yyscanner) +} + +%x STRING +%x ADDR6 + +%% +[0-9]+ { yylval->num = atoi(yytext); return TOK_INTEGER; } + +interface { yylval->str = yytext; return TOK_INTERFACE; } +bind { yylval->str = yytext; return TOK_BIND; } +mtu { yylval->str = yytext; return TOK_MTU; } +mode { yylval->str = yytext; return TOK_MODE; } +protocol { yylval->str = yytext; return TOK_PROTOCOL; } +peer { yylval->str = yytext; return TOK_PEER; } + +[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} { + if (!inet_pton(AF_INET, yytext, &yylval->addr)) + exit_error(ctx, "config error: invalid address"); + + return TOK_ADDR; + } + +any { yylval->str = yytext; return TOK_ANY; } +float { yylval->str = yytext; return TOK_FLOAT; } +tap { yylval->str = yytext; return TOK_TAP; } +tun { yylval->str = yytext; return TOK_TUN; } + +[A-Za-z_][A-Za-z0-9_]* { yylval->str = yytext; return TOK_IDENTIFIER; } + +[;:\{\}] { return *yytext; } + +[ \t\n] ; + +\" BEGIN(STRING); +[^"]* { yylval->str = yytext; return TOK_STRING; } +\" BEGIN(INITIAL); + +\[ BEGIN(ADDR6); +[^\]]+ { + if (!inet_pton(AF_INET6, yytext, &yylval->addr6)) + exit_error(ctx, "config error: invalid address"); + + return TOK_ADDR6; + } +\] BEGIN(INITIAL); + +. exit_error(ctx, "config error: invalid character"); +%% diff --git a/src/config.y b/src/config.y new file mode 100644 index 0000000..08c5050 --- /dev/null +++ b/src/config.y @@ -0,0 +1,106 @@ +%define api.pure +%name-prefix "fastd_config_" +%lex-param {fastd_context *ctx} +%lex-param {yyscan_t scanner} +%parse-param {fastd_context *ctx} +%parse-param {fastd_config *config} +%parse-param {yyscan_t scanner} + +%code requires { + #include +} + +%union { + int num; + char* str; + struct in_addr addr; + struct in6_addr addr6; +} + +%token TOK_INTEGER +%token TOK_STRING +%token TOK_IDENTIFIER + +%token TOK_INTERFACE +%token TOK_BIND +%token TOK_MTU +%token TOK_MODE +%token TOK_PROTOCOL +%token TOK_PEER + +%token TOK_ADDR +%token TOK_ADDR6 + +%token TOK_ANY +%token TOK_FLOAT +%token TOK_TAP +%token TOK_TUN + +/* %code top { + #define YY_DECL int fastd_config_lex(YYSTYPE *yylval_param, fastd_context *ctx, yyscan_t yyscanner) +}*/ + + +%code { + #include + YY_DECL; + + void fastd_config_error(fastd_context *ctx, fastd_config *config, void *scanner, char *s); +} + +%code provides { + #include + int fastd_config_parse (fastd_context *ctx, fastd_config *config, void *scanner); +} + +%% +config: config statement + | + ; + +statement: TOK_INTERFACE interface ';' + | TOK_BIND bind ';' + | TOK_MTU mtu ';' + | TOK_MODE mode ';' + | TOK_PROTOCOL protocol ';' + | TOK_PEER peer '{' peer_config '}' + ; + +interface: TOK_STRING { config->ifname = strdup($1); } + ; + +bind: TOK_ADDR + | TOK_ADDR ':' port + | TOK_ADDR6 + | TOK_ADDR6 ':' port + | TOK_ANY + | TOK_ANY ':' port + ; + +mtu: TOK_INTEGER { config->mtu = $1; } + ; + +mode: TOK_TAP { config->mode = MODE_TAP; } + | TOK_TUN { config->mode = MODE_TUN; } + ; + +protocol: TOK_STRING + ; + +peer: TOK_STRING + | + ; + +peer_config: peer_config peer_statement + | + ; + +peer_statement: ':' + ; + +port: TOK_INTEGER + ; +%% +void fastd_config_error(fastd_context *ctx, fastd_config *config, yyscan_t scanner, char *s) { + exit_error(ctx, "config error: %s", s); +} diff --git a/src/configure.c b/src/configure.c deleted file mode 100644 index 7473696..0000000 --- a/src/configure.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - 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 cae7c64..3b27e98 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -53,17 +53,17 @@ static void init_tuntap(fastd_context *ctx) { if (ctx->conf->ifname) strncpy(ifr.ifr_name, ctx->conf->ifname, IF_NAMESIZE-1); - switch (ctx->conf->protocol) { - case PROTOCOL_ETHERNET: + switch (ctx->conf->mode) { + case MODE_TAP: ifr.ifr_flags = IFF_TAP; break; - case PROTOCOL_IP: + case MODE_TUN: ifr.ifr_flags = IFF_TUN; break; default: - exit_bug(ctx, "invalid protocol"); + exit_bug(ctx, "invalid mode"); } ifr.ifr_flags |= IFF_NO_PI; @@ -166,7 +166,7 @@ static void handle_tasks(fastd_context *ctx) { break; case TASK_HANDLE_RECV: - if (ctx->conf->protocol == PROTOCOL_ETHERNET) { + if (ctx->conf->mode == MODE_TAP) { const fastd_eth_addr *src_addr = fastd_get_source_address(ctx, task->handle_recv.buffer); if (fastd_eth_addr_is_unicast(src_addr)) @@ -208,7 +208,7 @@ static void handle_tun(fastd_context *ctx) { fastd_peer *peer = NULL; - if (ctx->conf->protocol == PROTOCOL_ETHERNET) { + if (ctx->conf->mode == MODE_TAP) { const fastd_eth_addr *dest_addr = fastd_get_dest_address(ctx, buffer); if (fastd_eth_addr_is_unicast(dest_addr)) { peer = fastd_peer_find_by_eth_addr(ctx, dest_addr); diff --git a/src/fastd.h b/src/fastd.h index c42baa3..4af9f20 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -87,7 +87,7 @@ struct _fastd_config { struct sockaddr_in6 bind_addr_in6; uint16_t mtu; - fastd_protocol protocol; + fastd_mode mode; fastd_method *method; @@ -153,13 +153,13 @@ static inline void fastd_buffer_free(fastd_buffer buffer) { } static inline size_t fastd_max_packet_size(const fastd_context *ctx) { - switch (ctx->conf->protocol) { - case PROTOCOL_ETHERNET: + switch (ctx->conf->mode) { + case MODE_TAP: return ctx->conf->mtu+ETH_HLEN; - case PROTOCOL_IP: + case MODE_TUN: return ctx->conf->mtu; default: - exit_bug(ctx, "invalid protocol"); + exit_bug(ctx, "invalid mode"); } } diff --git a/src/handshake.c b/src/handshake.c index e30ab9f..19f15a9 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -74,8 +74,8 @@ void fastd_handshake_send(fastd_context *ctx, fastd_peer *peer) { request->req_id = ++peer->last_req_id; request->rsv = 0; - uint8_t protocol = ctx->conf->protocol; - handshake_add(ctx, &buffer, RECORD_PROTOCOL, 1, &protocol); + uint8_t mode = ctx->conf->mode; + handshake_add(ctx, &buffer, RECORD_MODE, 1, &mode); handshake_add(ctx, &buffer, RECORD_METHOD_NAME, method_len, ctx->conf->method->name); @@ -119,15 +119,15 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b uint8_t reply_code = REPLY_SUCCESS; uint8_t error_detail = 0; - if (!records[RECORD_PROTOCOL]) { + if (!records[RECORD_MODE]) { reply_code = REPLY_MANDATORY_MISSING; - error_detail = RECORD_PROTOCOL; + error_detail = RECORD_MODE; goto send_reply; } - if (lengths[RECORD_PROTOCOL] != 1 || *(uint8_t*)records[RECORD_PROTOCOL] != ctx->conf->protocol) { + if (lengths[RECORD_MODE] != 1 || *(uint8_t*)records[RECORD_MODE] != ctx->conf->mode) { reply_code = REPLY_UNACCEPTABLE_VALUE; - error_detail = RECORD_PROTOCOL; + error_detail = RECORD_MODE; goto send_reply; } diff --git a/src/packet.h b/src/packet.h index d442d18..b206663 100644 --- a/src/packet.h +++ b/src/packet.h @@ -42,7 +42,7 @@ typedef enum _fastd_handshake_record_type { RECORD_REPLY_CODE = 0, RECORD_ERROR_DETAIL, RECORD_FLAGS, - RECORD_PROTOCOL, + RECORD_MODE, RECORD_METHOD_NAME, RECORD_MAX, } fastd_handshake_record_type; diff --git a/src/peer.c b/src/peer.c index ab09a1a..3aecdc0 100644 --- a/src/peer.c +++ b/src/peer.c @@ -32,20 +32,20 @@ const fastd_eth_addr* fastd_get_source_address(const fastd_context *ctx, fastd_buffer buffer) { - switch (ctx->conf->protocol) { - case PROTOCOL_ETHERNET: + switch (ctx->conf->mode) { + case MODE_TAP: return (fastd_eth_addr*)&((struct ethhdr*)buffer.data)->h_source; default: - exit_bug(ctx, "invalid protocol"); + exit_bug(ctx, "invalid mode"); } } const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buffer buffer) { - switch (ctx->conf->protocol) { - case PROTOCOL_ETHERNET: + switch (ctx->conf->mode) { + case MODE_TAP: return (fastd_eth_addr*)&((struct ethhdr*)buffer.data)->h_dest; default: - exit_bug(ctx, "invalid protocol"); + exit_bug(ctx, "invalid mode"); } } diff --git a/src/types.h b/src/types.h index af577e3..61417fc 100644 --- a/src/types.h +++ b/src/types.h @@ -42,10 +42,10 @@ typedef enum _fastd_loglevel { LOG_DEBUG, } fastd_loglevel; -typedef enum _fastd_protocol { - PROTOCOL_ETHERNET, - PROTOCOL_IP, -} fastd_protocol; +typedef enum _fastd_mode { + MODE_TAP, + MODE_TUN, +} fastd_mode; typedef enum _fastd_peer_state { STATE_WAIT, -- cgit v1.2.3