From e499866cde13bb04b65e4aaac4f229cd8811f7f4 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Fri, 3 Dec 2010 01:40:38 +0000 Subject: added config file parser git-svn-id: https://svn.spreadspace.org/tcpproxy/trunk@24 e61f0598-a718-4e21-a8f0-0aadfa62ad6b --- src/Makefile | 12 +++ src/cfg_parse.y | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cfg_scan.lex | 62 +++++++++++++ src/configure | 2 + src/tcpproxy.c | 32 +++++-- 5 files changed, 380 insertions(+), 6 deletions(-) create mode 100644 src/cfg_parse.y create mode 100644 src/cfg_scan.lex (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 122abf4..7ee758e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,6 +33,8 @@ EXECUTABLE := tcpproxy C_OBJS := log.o \ options.o \ + cfg_scan.o \ + cfg_parse.o \ slist.o \ string_list.o \ sig_handler.o \ @@ -47,6 +49,14 @@ C_SRCS := $(C_OBJS:%.o=%.c) all: $(EXECUTABLE) +cfg_scan.c: cfg_scan.lex cfg_parse.h + $(FLEX) -Cem -o $@ cfg_scan.lex + +cfg_parse.h: cfg_parse.c + +cfg_parse.c: cfg_parse.y + $(BISON) -d -o $@ $< + %.d: %.c @set -e; rm -f $@; \ $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ @@ -77,6 +87,8 @@ clean: rm -f *.o rm -f *.d rm -f *.d.* + rm -f cfg_scan.c + rm -f cfg_parse.c cfg_parse.h rm -f $(EXECUTABLE) rm -f $(EXECUTABLE).exe diff --git a/src/cfg_parse.y b/src/cfg_parse.y new file mode 100644 index 0000000..fb6d97b --- /dev/null +++ b/src/cfg_parse.y @@ -0,0 +1,278 @@ +%{ +/* + * tcpproxy + * + * tcpproxy is a simple tcp connection proxy which combines the + * features of rinetd and 6tunnel. tcpproxy supports IPv4 and + * IPv6 and also supports connections from IPv6 to IPv4 + * endpoints and vice versa. + * + * + * Copyright (C) 2010-2011 Christian Pointner + * + * This file is part of tcpproxy. + * + * tcpproxy 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. + * + * tcpproxy 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 tcpproxy. If not, see . + */ + +#include +#include + +#include "datatypes.h" +#include "log.h" +#include "options.h" +#include "tcp.h" +#include "listener.h" + +void yyerror(const char *); +int yylex(void); + +int line_cnt = 1; +options_t* gopt; +listeners_t* glisteners; + +struct listener { + char* la_; + resolv_type_t lrt_; + char* lp_; + char* ra_; + resolv_type_t rrt_; + char* rp_; + char* sa_; +}; + +static struct listener* new_listener_struct() +{ + struct listener* l = malloc(sizeof(struct listener)); + l->la_ = NULL; + l->lrt_ = ANY; + l->lp_ = NULL; + l->ra_ = NULL; + l->rrt_ = ANY; + l->rp_ = NULL; + l->sa_ = NULL; +} + +static void clear_listener_struct(struct listener* l) +{ + if(l->la_) + free(l->la_); + if(l->lp_) + free(l->lp_); + if(l->ra_) + free(l->ra_); + if(l->rp_) + free(l->rp_); + if(l->sa_) + free(l->sa_); + + free(l); +} + +static void merge_listener_struct(struct listener* dest, struct listener* src) +{ + if(src->la_) { + if(dest->la_) + free(dest->la_); + dest->la_ = src->la_; + } + + if(src->lrt_ != ANY) + dest->lrt_ = src->lrt_; + + if(src->lp_) { + if(dest->lp_) + free(dest->lp_); + dest->lp_ = src->lp_; + } + + if(src->ra_) { + if(dest->ra_) + free(dest->ra_); + dest->ra_ = src->ra_; + } + + if(src->rrt_ != ANY) + dest->rrt_ = src->rrt_; + + if(src->rp_) { + if(dest->rp_) + free(dest->rp_); + dest->rp_ = src->rp_; + } + + if(src->sa_) { + if(dest->sa_) + free(dest->sa_); + dest->sa_ = src->sa_; + } + + free(src); +} + + +void yyinit(options_t* opt, listeners_t* listeners) +{ + gopt = opt; + glisteners = listeners; +} + +%} + +%union +{ + char null; + char *string; + int rtype; + struct listener* listener; +} + +%token TOK_OPEN; +%token TOK_CLOSE; +%token TOK_COLON; +%token TOK_SEMICOLON; +%token TOK_ASTERISK; +%token TOK_LISTEN; +%token TOK_RESOLV; +%token TOK_REMOTE; +%token TOK_REMOTE_RESOLV; +%token TOK_SOURCE; +%token TOK_IPV4; +%token TOK_IPV6; +%token TOK_NUMBER; +%token TOK_IPV4_ADDR; +%token TOK_IPV6_ADDR; +%token TOK_NAME; +%token TOK_HOSTNAME; + +%type listen +%type listen_head +%type listen_body +%type listen_body_element +%type remote +%type source +%type resolv +%type remote_resolv +%type resolv_type +%type service +%type host_or_addr +%% + +cfg: + | cfg listen + ; + +listen: listen_head TOK_OPEN listen_body TOK_CLOSE TOK_SEMICOLON +{ + merge_listener_struct($1, $3); + + int ret = listener_add(glisteners, $1->la_, $1->lrt_, $1->lp_, $1->ra_, $1->rrt_, $1->rp_, $1->sa_); + clear_listener_struct($1); + if(ret) { + listener_clear(glisteners); + options_clear(gopt); + log_close(); + exit(-1); + } +} +; + +listen_head: TOK_LISTEN host_or_addr service +{ + struct listener* l = new_listener_struct(); + l->la_ = $2; + l->lp_ = $3; + $$ = l; +} + | TOK_LISTEN TOK_ASTERISK service +{ + struct listener* l = new_listener_struct(); + l->lp_ = $3; + $$ = l; +} +; + +listen_body: listen_body_element + | listen_body listen_body_element +{ + merge_listener_struct($1, $2); + $$ = $1; +} +; + +listen_body_element: resolv TOK_SEMICOLON + | remote TOK_SEMICOLON + | remote_resolv TOK_SEMICOLON + | source TOK_SEMICOLON + ; + +remote: TOK_REMOTE TOK_COLON host_or_addr service +{ + struct listener* l = new_listener_struct(); + l->ra_ = $3; + l->rp_ = $4; + $$ = l; +} +; + +source: TOK_SOURCE TOK_COLON host_or_addr +{ + struct listener* l = new_listener_struct(); + l->sa_ = $3; + $$ = l; +} +; + +resolv: TOK_RESOLV TOK_COLON resolv_type +{ + struct listener* l = new_listener_struct(); + l->lrt_ = $3; + $$ = l; +} +; + +remote_resolv: TOK_REMOTE_RESOLV TOK_COLON resolv_type +{ + struct listener* l = new_listener_struct(); + l->rrt_ = $3; + $$ = l; +} +; + + +resolv_type: TOK_IPV4 + | TOK_IPV6 + ; + +service: TOK_NUMBER + | TOK_NAME + ; + +host_or_addr: TOK_NUMBER + | TOK_NAME + | TOK_HOSTNAME + | TOK_IPV4_ADDR + | TOK_IPV6_ADDR + ; +%% + +void yyerror (const char *string) +{ + log_printf(ERROR, "%s:%d %s\n", gopt->config_file_, line_cnt, string); + listener_clear(glisteners); + options_clear(gopt); + log_close(); + exit(1); +} + diff --git a/src/cfg_scan.lex b/src/cfg_scan.lex new file mode 100644 index 0000000..a63490d --- /dev/null +++ b/src/cfg_scan.lex @@ -0,0 +1,62 @@ +%{ +/* + * tcpproxy + * + * tcpproxy is a simple tcp connection proxy which combines the + * features of rinetd and 6tunnel. tcpproxy supports IPv4 and + * IPv6 and also supports connections from IPv6 to IPv4 + * endpoints and vice versa. + * + * + * Copyright (C) 2010-2011 Christian Pointner + * + * This file is part of tcpproxy. + * + * tcpproxy 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. + * + * tcpproxy 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 tcpproxy. If not, see . + */ + +#include "cfg_parse.h" + +#include "tcp.h" + +extern int line_cnt; +%} + +%option noyywrap + +%% + +\s*"#".*\n line_cnt++; +\{ return TOK_OPEN; +\} return TOK_CLOSE; +\: return TOK_COLON; +\; return TOK_SEMICOLON; +\* return TOK_ASTERISK; +"listen" return TOK_LISTEN; +"resolv" return TOK_RESOLV; +"remote" return TOK_REMOTE; +"remote-resolv" return TOK_REMOTE_RESOLV; +"source" return TOK_SOURCE; +"ipv4" yylval.rtype = IPV4_ONLY; return TOK_IPV4; +"ipv6" yylval.rtype = IPV6_ONLY; return TOK_IPV6; +[0-9]+ yylval.string = strdup(yytext); return TOK_NUMBER; +[0-9\.]+ yylval.string = strdup(yytext); return TOK_IPV4_ADDR; +[0-9a-fA-F:]+ yylval.string = strdup(yytext); return TOK_IPV6_ADDR; +[a-zA-Z0-9\-]+ yylval.string = strdup(yytext); return TOK_NAME; +[a-zA-Z0-9\-\.]+ yylval.string = strdup(yytext); return TOK_HOSTNAME; +\n line_cnt++; +[ \t]+ /* ignore whitespace */; + +%% + diff --git a/src/configure b/src/configure index d1fa13d..4afa358 100755 --- a/src/configure +++ b/src/configure @@ -143,6 +143,8 @@ CFLAGS := $CFLAGS LDFLAGS := $LDFLAGS STRIP := strip INSTALL := install +FLEX := flex +BISON := bison PREFIX := '$PREFIX' SBINDIR := '$SBINDIR' diff --git a/src/tcpproxy.c b/src/tcpproxy.c index 149fdf0..ef71cb4 100644 --- a/src/tcpproxy.c +++ b/src/tcpproxy.c @@ -40,6 +40,11 @@ #include "listener.h" #include "clients.h" +extern FILE *yyin; +extern void yyinit(options_t* opt, listeners_t* listeners); +extern int yyparse(void); + + int main_loop(options_t* opt, listeners_t* listeners) { log_printf(INFO, "entering main loop"); @@ -145,12 +150,27 @@ int main(int argc, char* argv[]) log_close(); exit(-1); } - ret = listener_add(&listeners, opt.local_addr_, opt.lresolv_type_, opt.local_port_, opt.remote_addr_, opt.rresolv_type_, opt.remote_port_, opt.source_addr_); - if(ret) { - listener_clear(&listeners); - options_clear(&opt); - log_close(); - exit(-1); + + if(opt.local_port_) { + ret = listener_add(&listeners, opt.local_addr_, opt.lresolv_type_, opt.local_port_, opt.remote_addr_, opt.rresolv_type_, opt.remote_port_, opt.source_addr_); + if(ret) { + listener_clear(&listeners); + options_clear(&opt); + log_close(); + exit(-1); + } + } else { + yyin = fopen(opt.config_file_, "r"); + if(!yyin) { + log_printf(ERROR, "can't open config file %s: %s", opt.config_file_, strerror(errno)); + listener_clear(&listeners); + options_clear(&opt); + log_close(); + exit(-1); + } + + yyinit(&opt, &listeners); + yyparse(); } priv_info_t priv; -- cgit v1.2.3