summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile15
-rw-r--r--src/cfg_parse.y273
-rw-r--r--src/cfg_parser.h36
-rw-r--r--src/cfg_parser.rl216
-rw-r--r--src/cfg_scan.lex62
-rwxr-xr-xsrc/configure3
-rw-r--r--src/tcpproxy.c35
7 files changed, 267 insertions, 373 deletions
diff --git a/src/Makefile b/src/Makefile
index 5a4cebf..387fbec 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -33,8 +33,7 @@ EXECUTABLE := tcpproxy
C_OBJS := log.o \
options.o \
- cfg_scan.o \
- cfg_parse.o \
+ cfg_parser.o \
slist.o \
string_list.o \
sig_handler.o \
@@ -49,13 +48,8 @@ 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 $@ $<
+cfg_parser.c: cfg_parser.rl
+ $(RAGEL) -C -G2 -o $@ $<
%.d: %.c
@set -e; rm -f $@; \
@@ -87,8 +81,7 @@ 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 cfg_parser.c
rm -f $(EXECUTABLE)
cleanall: clean
diff --git a/src/cfg_parse.y b/src/cfg_parse.y
deleted file mode 100644
index a18abd5..0000000
--- a/src/cfg_parse.y
+++ /dev/null
@@ -1,273 +0,0 @@
-%{
-/*
- * 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 <equinox@spreadspace.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#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;
-const char* config_file_;
-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(const char* config_file, listeners_t* listeners)
-{
- config_file_ = config_file;
- glisteners = listeners;
-}
-
-%}
-
-%union
-{
- char null;
- char *string;
- int rtype;
- struct listener* listener;
-}
-
-%token <null> TOK_OPEN;
-%token <null> TOK_CLOSE;
-%token <null> TOK_COLON;
-%token <null> TOK_SEMICOLON;
-%token <null> TOK_ASTERISK;
-%token <null> TOK_LISTEN;
-%token <null> TOK_RESOLV;
-%token <null> TOK_REMOTE;
-%token <null> TOK_REMOTE_RESOLV;
-%token <null> TOK_SOURCE;
-%token <rtype> TOK_IPV4;
-%token <rtype> TOK_IPV6;
-%token <string> TOK_NUMBER;
-%token <string> TOK_IPV4_ADDR;
-%token <string> TOK_IPV6_ADDR;
-%token <string> TOK_NAME;
-%token <string> TOK_HOSTNAME;
-
-%type <null> listen
-%type <listener> listen_head
-%type <listener> listen_body
-%type <listener> listen_body_element
-%type <listener> remote
-%type <listener> source
-%type <listener> resolv
-%type <listener> remote_resolv
-%type <rtype> resolv_type
-%type <string> service
-%type <string> host_or_addr
-
-%error-verbose
-
-%%
-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) {
- YYABORT;
- }
-}
-;
-
-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", config_file_, line_cnt, string);
-}
-
diff --git a/src/cfg_parser.h b/src/cfg_parser.h
new file mode 100644
index 0000000..d96c705
--- /dev/null
+++ b/src/cfg_parser.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <equinox@spreadspace.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TCPPROXY_cfg_parser_h_INCLUDED
+#define TCPPROXY_cfg_parser_h_INCLUDED
+
+#include "listener.h"
+
+int parse_listener(char* p, char* pe, listeners_t* listener);
+int read_configfile(const char* filename, listeners_t* listener);
+
+#endif
diff --git a/src/cfg_parser.rl b/src/cfg_parser.rl
new file mode 100644
index 0000000..a75a580
--- /dev/null
+++ b/src/cfg_parser.rl
@@ -0,0 +1,216 @@
+/*
+ * 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 <equinox@spreadspace.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "datatypes.h"
+#include "log.h"
+#include "options.h"
+#include "tcp.h"
+#include "listener.h"
+
+struct listener {
+ char* la_;
+ resolv_type_t lrt_;
+ char* lp_;
+ char* ra_;
+ resolv_type_t rrt_;
+ char* rp_;
+ char* sa_;
+};
+
+static void init_listener_struct(struct listener* l)
+{
+ if(!l) return;
+
+ 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) return;
+
+ 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_);
+
+ init_listener_struct(l);
+}
+
+static int owrt_string(char** dest, char* start, char* end)
+{
+ if(!dest || start >= end)
+ return -1;
+
+ if(*dest) free(*dest);
+ *dest = strndup(start, end - start);
+ if(!(*dest))
+ return -2;
+
+ return 0;
+}
+
+%%{
+ machine cfg_parser;
+
+ action set_cpy_start { cpy_start = fpc; }
+ action set_local_addr { ret = owrt_string(&(lst.la_), cpy_start, fpc); cpy_start = NULL; }
+ action set_local_port { ret = owrt_string(&(lst.lp_), cpy_start, fpc); cpy_start = NULL; }
+ action set_local_resolv4 { lst.lrt_ = IPV4_ONLY; }
+ action set_local_resolv6 { lst.lrt_ = IPV6_ONLY; }
+
+ action set_remote_addr { ret = owrt_string(&(lst.ra_), cpy_start, fpc); cpy_start = NULL; }
+ action set_remote_port { ret = owrt_string(&(lst.rp_), cpy_start, fpc); cpy_start = NULL; }
+ action set_remote_resolv4 { lst.rrt_ = IPV4_ONLY; }
+ action set_remote_resolv6 { lst.rrt_ = IPV6_ONLY; }
+
+ action set_source_addr { ret = owrt_string(&(lst.sa_), cpy_start, fpc); cpy_start = NULL; }
+
+ action add_listener {
+ log_printf(DEBUG, "line %d: adding listner: %s : %s -> %s : %s (%s)", cur_line, lst.la_ ? lst.la_ : "(null)", lst.lp_ ? lst.lp_ : "(null)", lst.ra_ ? lst.ra_ : "(null)", lst.rp_ ? lst.rp_ : "(null)", lst.sa_ ? lst.sa_ : "(null)");
+ ret = listener_add(listener, lst.la_, lst.lrt_, lst.lp_, lst.ra_, lst.rrt_, lst.rp_, lst.sa_);
+ clear_listener_struct(&lst);
+ }
+
+ newline = '\n' @{cur_line++;};
+ ws = ( " " | "\t" );
+ wsn= ( ws | newline );
+
+ number = [0-9]+;
+ ipv4_addr = [0-9.]+;
+ ipv6_addr = [0-9a-fA-F:]+;
+ name = [a-zA-Z0-9\-]+;
+ host_name = [a-zA-Z0-9\-.]+;
+ tok_ipv4 = "ipv4";
+ tok_ipv6 = "ipv6";
+
+ host_or_addr = ( host_name | 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;
+ lresolv = ( tok_ipv4 @set_local_resolv4 | tok_ipv6 @set_local_resolv6 );
+
+ remote_addr = host_or_addr >set_cpy_start %set_remote_addr;
+ remote_port = service >set_cpy_start %set_remote_port;
+ rresolv = ( tok_ipv4 @set_remote_resolv4 | tok_ipv6 @set_remote_resolv6 );
+
+ source_addr = host_or_addr >set_cpy_start %set_source_addr;
+
+ resolv = "resolv" ws* ":" ws+ lresolv ws* ";";
+ remote = "remote" ws* ":" ws+ remote_addr ws+ remote_port ws* ";";
+ remote_resolv = "remote-resolv" ws* ":" ws+ rresolv ws* ";";
+ source = "source" ws* ":" ws+ source_addr ws* ";";
+
+ listen_head = 'listen' ws+ local_addr ws+ local_port;
+ listen_body = '{' ( wsn+ | resolv | remote | remote_resolv | source )* '};' @add_listener;
+
+ main := ( listen_head wsn* listen_body | wsn+ )*;
+}%%
+
+
+int parse_listener(char* p, char* pe, listeners_t* listener)
+{
+ int cs, ret = 0, cur_line = 1;
+
+ %% write data;
+ %% write init;
+
+ char* cpy_start = NULL;
+ struct listener lst;
+ init_listener_struct(&lst);
+
+ %% write exec;
+
+ if(cs == cfg_parser_error) {
+ log_printf(ERROR, "syntax error in line %d", cur_line);
+ }
+
+ clear_listener_struct(&lst);
+
+ return ret;
+}
+
+int read_configfile(const char* filename, listeners_t* listener)
+{
+ int fd = open(filename, 0);
+ if(fd < 0) {
+ log_printf(ERROR, "open('%s') failed: %s", filename, strerror(errno));
+ return -1;
+ }
+
+ struct stat sb;
+ if(fstat(fd, &sb) == -1) {
+ log_printf(ERROR, "fstat() error: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ if(!S_ISREG(sb.st_mode)) {
+ log_printf(ERROR, "%s no regular file", filename);
+ close(fd);
+ return -1;
+ }
+
+ char* p = (char*)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if(p == MAP_FAILED) {
+ log_printf(ERROR, "mmap() error: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ log_printf(DEBUG, "mapped %ld bytes from file %s", sb.st_size, filename);
+ int ret = parse_listener(p, p + sb.st_size, listener);
+
+ if(munmap(p, sb.st_size) == -1) {
+ log_printf(ERROR, "munmap() error: %s", strerror(errno));
+ return -1;
+ }
+ log_printf(DEBUG, "unmapped file %s", filename);
+
+ return ret;
+}
diff --git a/src/cfg_scan.lex b/src/cfg_scan.lex
deleted file mode 100644
index a63490d..0000000
--- a/src/cfg_scan.lex
+++ /dev/null
@@ -1,62 +0,0 @@
-%{
-/*
- * 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 <equinox@spreadspace.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#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 b07190b..53d457d 100755
--- a/src/configure
+++ b/src/configure
@@ -143,8 +143,7 @@ CFLAGS := $CFLAGS
LDFLAGS := $LDFLAGS
STRIP := strip
INSTALL := install
-FLEX := flex
-BISON := bison
+RAGEL := ragel
PREFIX := '$PREFIX'
BINDIR := '$BINDIR'
diff --git a/src/tcpproxy.c b/src/tcpproxy.c
index 3e30338..273aad0 100644
--- a/src/tcpproxy.c
+++ b/src/tcpproxy.c
@@ -1,14 +1,14 @@
/*
* 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
+ * 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 <equinox@spreadspace.org>
- *
+ *
* This file is part of tcpproxy.
*
* tcpproxy is free software: you can redistribute it and/or modify
@@ -39,11 +39,7 @@
#include "listener.h"
#include "clients.h"
-
-extern FILE *yyin;
-extern void yyinit(const char* config_file, listeners_t* listeners);
-extern int yyparse(void);
-
+#include "cfg_parser.h"
int main_loop(options_t* opt, listeners_t* listeners)
{
@@ -112,7 +108,7 @@ int main(int argc, char* argv[])
options_print_version();
}
- if(ret != -2 && ret != -3)
+ if(ret != -2 && ret != -3)
options_print_usage();
if(ret == -1 || ret == -3)
@@ -132,7 +128,7 @@ int main(int argc, char* argv[])
case -4: fprintf(stderr, "this log target is only allowed once: '%s', exitting\n", (char*)(tmp->data_)); break;
default: fprintf(stderr, "syntax error near: '%s', exitting\n", (char*)(tmp->data_)); break;
}
-
+
options_clear(&opt);
log_close();
exit(ret);
@@ -160,18 +156,7 @@ int main(int argc, char* argv[])
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.config_file_, &listeners);
- int ret = yyparse();
- fclose(yyin);
+ ret = read_configfile(opt.config_file_, &listeners);
if(ret || !slist_length(&listeners)) {
if(!ret)
log_printf(ERROR, "no listeners defined in config file %s", opt.config_file_);
@@ -212,7 +197,7 @@ int main(int argc, char* argv[])
options_clear(&opt);
log_close();
exit(-1);
- }
+ }
if(opt.daemonize_) {
pid_t oldpid = getpid();