From ef19b2d2d034a4092755dceb8cf9d2aab0b85445 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Tue, 6 Jan 2015 21:31:10 +0000 Subject: added first version for config file parser --- src/Makefile | 12 ++++ src/cfg_parser.h | 56 ++++++++++++++++ src/cfg_parser.rl | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/configure | 1 + src/options.c | 12 ++++ src/options.h | 1 + src/uanytun.c | 16 ++--- 7 files changed, 286 insertions(+), 9 deletions(-) create mode 100644 src/cfg_parser.h create mode 100644 src/cfg_parser.rl (limited to 'src') diff --git a/src/Makefile b/src/Makefile index feccbaa..3332997 100644 --- a/src/Makefile +++ b/src/Makefile @@ -59,6 +59,7 @@ OBJ := log.o \ sig_handler.o \ sysexec.o \ options.o \ + cfg_parser.o \ tun.o \ udp.o \ plain_packet.o \ @@ -78,6 +79,15 @@ SRC := $(OBJ:%.o=%.c) all: $(EXECUTABLE) +cfg_parser.c: cfg_parser.rl + $(RAGEL) -C -G2 -o $@ $< + +cfg_parser.dot: cfg_parser.rl + $(RAGEL) -V -p -o $@ $< + +cfg_parser.png: cfg_parser.dot + @dot -Tpng $< > $@ + %.d: %.c @set -e; rm -f $@; \ $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ @@ -109,6 +119,8 @@ clean: rm -f *.o rm -f *.d rm -f *.d.* + rm -f cfg_parser.c + rm -f cfg_parser.png cfg_parser.dot rm -f $(EXECUTABLE) cleanall: clean diff --git a/src/cfg_parser.h b/src/cfg_parser.h new file mode 100644 index 0000000..1c030c0 --- /dev/null +++ b/src/cfg_parser.h @@ -0,0 +1,56 @@ +/* + * uAnytun + * + * uAnytun is a tiny implementation of SATP. Unlike Anytun which is a full + * featured implementation uAnytun has no support for multiple connections + * or synchronisation. It is a small single threaded implementation intended + * to act as a client on small platforms. + * The secure anycast tunneling protocol (satp) defines a protocol used + * for communication between any combination of unicast and anycast + * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel + * mode and allows tunneling of every ETHER TYPE protocol (e.g. + * ethernet, ip, arp ...). satp directly includes cryptography and + * message authentication based on the methods used by SRTP. It is + * intended to deliver a generic, scaleable and secure solution for + * tunneling and relaying of packets of any protocol. + * + * + * Copyright (C) 2007-2014 Christian Pointner + * + * This file is part of uAnytun. + * + * uAnytun 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 3 of the License, or + * any later version. + * + * uAnytun 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. + * + * You should have received a copy of the GNU General Public License + * along with uAnytun. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef UANYTUN_cfg_parser_h_INCLUDED +#define UANYTUN_cfg_parser_h_INCLUDED + +#include "options.h" + +int read_configfile(const char* filename, options_t* opt); + +#endif diff --git a/src/cfg_parser.rl b/src/cfg_parser.rl new file mode 100644 index 0000000..98118a7 --- /dev/null +++ b/src/cfg_parser.rl @@ -0,0 +1,197 @@ +/* + * uAnytun + * + * uAnytun is a tiny implementation of SATP. Unlike Anytun which is a full + * featured implementation uAnytun has no support for multiple connections + * or synchronisation. It is a small single threaded implementation intended + * to act as a client on small platforms. + * The secure anycast tunneling protocol (satp) defines a protocol used + * for communication between any combination of unicast and anycast + * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel + * mode and allows tunneling of every ETHER TYPE protocol (e.g. + * ethernet, ip, arp ...). satp directly includes cryptography and + * message authentication based on the methods used by SRTP. It is + * intended to deliver a generic, scaleable and secure solution for + * tunneling and relaying of packets of any protocol. + * + * + * Copyright (C) 2007-2014 Christian Pointner + * + * This file is part of uAnytun. + * + * uAnytun 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 3 of the License, or + * any later version. + * + * uAnytun 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. + * + * You should have received a copy of the GNU General Public License + * along with uAnytun. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "datatypes.h" +#include "options.h" + +static int owrt_string(char** dest, char* start, char* end) +{ + if(!dest || start >= end) + return -1; + + if(*dest) free(*dest); + int n = end - start; + *dest = malloc(n+1); + if(!(*dest)) + return -2; + + memcpy(*dest, start, n); + (*dest)[n] = 0; + + return 0; +} + +%%{ + machine cfg_parser; + + action set_cpy_start { cpy_start = fpc; } + action set_local_addr { ret = owrt_string(&(opt->local_addr_), cpy_start, fpc); cpy_start = NULL; } + action set_local_port { ret = owrt_string(&(opt->local_port_), cpy_start, fpc); cpy_start = NULL; } + action set_remote_addr { ret = owrt_string(&(opt->remote_addr_), cpy_start, fpc); cpy_start = NULL; } + action set_remote_port { ret = owrt_string(&(opt->remote_port_), cpy_start, fpc); cpy_start = NULL; } + action logerror { + if(fpc == eof) + fprintf(stderr, "config file syntax error: unexpected end of file\n"); + else + fprintf(stderr, "config file syntax error at line %d\n", cur_line); + + fgoto *cfg_parser_error; + } + + newline = '\n' @{cur_line++;}; + ws = [ \t]; + comment = '#' [^\n]* newline; + ign = ( ws | comment | newline | [\v\f\r] ); + + number = [0-9]+; + ipv4_addr = [0-9.]+; + ipv6_addr = [0-9a-fA-F:]+; + name = [a-zA-Z0-9\-]+; + host_name = [a-zA-Z0-9\-.]+; + + host_or_addr = ( host_name | ipv4_addr | ipv6_addr ); + service = ( number | name ); + + local_addr = ( '*' | host_or_addr >set_cpy_start %set_local_addr ); + local_port = service >set_cpy_start %set_local_port; + remote_addr = host_or_addr >set_cpy_start %set_remote_addr; + remote_port = service >set_cpy_start %set_remote_port; + + opt_laddr = "interface" ws* "=" ws* local_addr ign* newline; + opt_lport = "port" ws* "=" ws* local_port ign* newline; + opt_raddr = "remote-host" ws* "=" ws* remote_addr ign* newline; + opt_rport = "remote-port" ws* "=" ws* remote_port ign* newline; + + option = ( opt_laddr | opt_lport | opt_raddr | opt_rport ); + + section_head = '[' name ']'; + section_body = ( ign | option )+; + + main := ( section_head ign* section_body | ign+ )* $!logerror; +}%% + + +static int parse_options(char* p, char* pe, options_t* opt) +{ + int cs, ret = 0, cur_line = 1; + + %% write data; + %% write init; + + char* cpy_start = NULL; + char* eof = pe; + %% write exec; + + if(cs == cfg_parser_error) { + /* revert config updates */ + ret = -1; + } + else { + /* TODO: apply config update */ + ret = 0; + } + + return ret; +} + +int read_configfile(const char* filename, options_t* opt) +{ + int fd = open(filename, 0); + if(fd < 0) { + fprintf(stderr, "config: open('%s') failed: %s\n", filename, strerror(errno)); + return -1; + } + + struct stat sb; + if(fstat(fd, &sb) == -1) { + fprintf(stderr, "config: fstat() error: %s\n", strerror(errno)); + close(fd); + return -1; + } + + if(!sb.st_size) { + fprintf(stderr, "config: '%s' is empty\n", filename); + close(fd); + return -1; + } + + if(!S_ISREG(sb.st_mode)) { + fprintf(stderr, "config: '%s' is not a regular file\n", filename); + close(fd); + return -1; + } + + char* p = (char*)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); + if(p == MAP_FAILED) { + fprintf(stderr, "config: mmap() error: %s\n", strerror(errno)); + close(fd); + return -1; + } + close(fd); + + fprintf(stderr, "config: mapped %ld bytes from file %s at address 0x%08lX\n", sb.st_size, filename, (unsigned long int)p); + int ret = parse_options(p, p + sb.st_size, opt); + + if(munmap(p, sb.st_size) == -1) { + fprintf(stderr, "config: munmap() error: %s\n", strerror(errno)); + return -1; + } + fprintf(stderr, "config: unmapped '%s'\n", filename); + + return ret; +} diff --git a/src/configure b/src/configure index 16d5cc7..8b051c3 100755 --- a/src/configure +++ b/src/configure @@ -238,6 +238,7 @@ CFLAGS := $CFLAGS LDFLAGS := $LDFLAGS STRIP := strip INSTALL := install +RAGEL := ragel PREFIX := $PREFIX SBINDIR := $SBINDIR diff --git a/src/options.c b/src/options.c index c3038bb..7f44c41 100644 --- a/src/options.c +++ b/src/options.c @@ -57,6 +57,7 @@ #include #include "log.h" +#include "cfg_parser.h" #ifndef NO_CRYPT #include "auth_algo.h" @@ -250,6 +251,12 @@ int options_parse(options_t* opt, int argc, char* argv[]) return -1; else if(!strcmp(str,"-v") || !strcmp(str,"--version")) return -5; + else if(!strcmp(str,"-F") || !strcmp(str,"--config-file")) { + if(argc < 1) return i; + if(read_configfile(argv[i+1], opt)) return -6; + argc--; + i++; + } PARSE_INVERSE_BOOL_PARAM("-D","--nodaemonize", opt->daemonize_) PARSE_STRING_PARAM("-u","--username", opt->username_) PARSE_STRING_PARAM("-g","--groupname", opt->groupname_) @@ -351,6 +358,7 @@ void options_default(options_t* opt) return; opt->progname_ = strdup("uanytun"); + opt->config_file_ = NULL; opt->daemonize_ = 1; opt->username_ = NULL; opt->groupname_ = NULL; @@ -395,6 +403,8 @@ void options_clear(options_t* opt) if(opt->progname_) free(opt->progname_); + if(opt->config_file_) + free(opt->config_file_); if(opt->username_) free(opt->username_); if(opt->groupname_) @@ -441,6 +451,7 @@ void options_print_usage() printf("USAGE:\n"); printf("uanytun [-h|--help] prints this...\n"); printf(" [-v|--version] print version info and exit\n"); + printf(" [-F|--config-file] path to the configuration file\n"); printf(" [-D|--nodaemonize] don't run in background\n"); printf(" [-u|--username] change to this user\n"); printf(" [-g|--groupname] change to this group\n"); @@ -496,6 +507,7 @@ void options_print(options_t* opt) return; printf("progname: '%s'\n", opt->progname_); + printf("config-file: '%s'\n", opt->config_file_); printf("daemonize: %d\n", opt->daemonize_); printf("username: '%s'\n", opt->username_); printf("groupname: '%s'\n", opt->groupname_); diff --git a/src/options.h b/src/options.h index 8f3593f..8a7290d 100644 --- a/src/options.h +++ b/src/options.h @@ -65,6 +65,7 @@ typedef enum role_enum role_t; struct options_struct { char* progname_; + char* config_file_; int daemonize_; char* username_; char* groupname_; diff --git a/src/uanytun.c b/src/uanytun.c index 159f773..3baea2c 100644 --- a/src/uanytun.c +++ b/src/uanytun.c @@ -307,21 +307,17 @@ int main(int argc, char* argv[]) if(ret) { if(ret > 0) { fprintf(stderr, "syntax error near: %s\n\n", argv[ret]); - } - if(ret == -2) { + } else if(ret == -2) { fprintf(stderr, "memory error on options_parse, exitting\n"); - } - if(ret == -3) { + } else if(ret == -3) { fprintf(stderr, "syntax error: -4 and -6 are mutual exclusive\n\n"); - } - if(ret == -4) { + } else if(ret == -4) { fprintf(stderr, "syntax error: unknown role name\n\n"); - } - if(ret == -5) { + } else if(ret == -5) { options_print_version(); } - if(ret != -2 && ret != -5) + if(ret != -2 && ret != -5 && ret != -6) options_print_usage(); if(ret == -1 || ret == -5) @@ -352,6 +348,8 @@ int main(int argc, char* argv[]) log_printf(NOTICE, "just started..."); options_parse_post(&opt); + options_print(&opt); + priv_info_t priv; if(opt.username_) if(priv_init(&priv, opt.username_, opt.groupname_)) { -- cgit v1.2.3