summaryrefslogtreecommitdiff
path: root/src/cfg_parser.rl
diff options
context:
space:
mode:
Diffstat (limited to 'src/cfg_parser.rl')
-rw-r--r--src/cfg_parser.rl216
1 files changed, 216 insertions, 0 deletions
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;
+}