From e7ce9290200a3f4b2bad3d799a504ce03d33c944 Mon Sep 17 00:00:00 2001 From: yrutschle Date: Thu, 29 Nov 2018 11:56:33 +0100 Subject: [PATCH 1/5] config file now read to struct with c2s; command line no longer works --- Makefile | 7 +- common.c | 69 +++++++----------- common.h | 5 +- echosrv.c | 2 + example.cfg | 5 +- probe.c | 131 +++++++++++++++++----------------- probe.h | 16 +++-- sslh-conf.c | 79 ++++++++++++++------- sslh-conf.h | 48 ++++++++----- sslh-fork.c | 12 ++-- sslh-main.c | 193 +++++++++++++++++++++++++++++++++----------------- sslh-select.c | 28 ++++---- sslhconf.cfg | 107 ++++++++++++++++------------ test.cfg | 6 +- tls.c | 39 +++++----- tls.h | 2 +- 16 files changed, 435 insertions(+), 314 deletions(-) diff --git a/Makefile b/Makefile index aeafb7f..2fbeaa2 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ CC ?= gcc CFLAGS ?=-Wall -g $(CFLAGS_COV) LIBS= -OBJS=common.o sslh-main.o probe.o tls.o +OBJS=sslh-conf.o common.o sslh-main.o probe.o tls.o CONDITIONAL_TARGETS= @@ -72,6 +72,9 @@ sslh: sslh-fork sslh-select $(OBJS): version.h +sslh-conf.c: sslhconf.cfg + conf2struct sslhconf.cfg + sslh-fork: version.h $(OBJS) sslh-fork.o Makefile common.h $(CC) $(CFLAGS) $(LDFLAGS) -o sslh-fork sslh-fork.o $(OBJS) $(LIBS) #strip sslh-fork @@ -112,7 +115,7 @@ uninstall: update-rc.d sslh remove distclean: clean - rm -f tags cscope.* + rm -f tags sslh-conf.c sslh-conf.h cscope.* clean: rm -f sslh-fork sslh-select echosrv version.h $(MAN) systemd-sslh-generator *.o *.gcov *.gcno *.gcda *.png *.html *.css *.info diff --git a/common.c b/common.c index 3409fc8..c0bdc54 100644 --- a/common.c +++ b/common.c @@ -16,6 +16,7 @@ #include "common.h" #include "probe.h" +#include "sslh-conf.h" /* Added to make the code compilable under CYGWIN * */ @@ -30,18 +31,9 @@ #endif /* - * Settings that depend on the command line. They're set in main(), but also - * used in other places in common.c, and it'd be heavy-handed to pass it all as - * parameters + * Settings that depend on the command line or the config file */ -int verbose = 0; -int probing_timeout = 2; -int inetd = 0; -int foreground = 0; -int background = 0; -int transparent = 0; -int numeric = 0; -const char *user_name, *pid_file, *chroot_path, *facility = "auth"; +struct config_item cfg; struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */ @@ -122,7 +114,7 @@ int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list) exit(1); } - if (verbose) + if (cfg.verbose) fprintf(stderr, "listening to %d addresses\n", num_addr); *sockfd = malloc(num_addr * sizeof(*sockfd[0])); @@ -272,9 +264,9 @@ int connect_addr(struct connection *cnx, int fd_from) for (a = cnx->proto->saddr; a; a = a->ai_next) { /* When transparent, make sure both connections use the same address family */ - if (transparent && a->ai_family != from.ai_addr->sa_family) + if (cfg.transparent && a->ai_family != from.ai_addr->sa_family) continue; - if (verbose) + if (cfg.verbose) fprintf(stderr, "connecting to %s family %d len %d\n", sprintaddr(buf, sizeof(buf), a), a->ai_addr->sa_family, a->ai_addrlen); @@ -283,16 +275,16 @@ int connect_addr(struct connection *cnx, int fd_from) fd = socket(a->ai_family, SOCK_STREAM, 0); if (fd == -1) { log_message(LOG_ERR, "forward to %s failed:socket: %s\n", - cnx->proto->description, strerror(errno)); + cnx->proto->name, strerror(errno)); } else { - if (transparent) { + if (cfg.transparent) { res = bind_peer(fd, fd_from); CHECK_RES_RETURN(res, "bind_peer"); } res = connect(fd, a->ai_addr, a->ai_addrlen); if (res == -1) { log_message(LOG_ERR, "forward to %s failed:connect: %s\n", - cnx->proto->description, strerror(errno)); + cnx->proto->name, strerror(errno)); close(fd); } else { if (cnx->proto->keepalive) { @@ -312,7 +304,7 @@ int defer_write(struct queue *q, void* data, int data_size) { char *p; ptrdiff_t data_offset = q->deferred_data - q->begin_deferred_data; - if (verbose) + if (cfg.verbose) fprintf(stderr, "**** writing deferred on fd %d\n", q->fd); p = realloc(q->begin_deferred_data, data_offset + q->deferred_data_size + data_size); @@ -335,7 +327,7 @@ int flush_deferred(struct queue *q) { int n; - if (verbose) + if (cfg.verbose) fprintf(stderr, "flushing deferred data to fd %d\n", q->fd); n = write(q->fd, q->deferred_data, q->deferred_data_size); @@ -395,7 +387,7 @@ int fd2fd(struct queue *target_q, struct queue *from_q) if (size_r == -1) { switch (errno) { case EAGAIN: - if (verbose) + if (cfg.verbose) fprintf(stderr, "reading 0 from %d\n", from); return FD_NODATA; @@ -444,7 +436,7 @@ char* sprintaddr(char* buf, size_t size, struct addrinfo *a) res = getnameinfo(a->ai_addr, a->ai_addrlen, host, sizeof(host), serv, sizeof(serv), - numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 ); + cfg.numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 ); if (res) { log_message(LOG_ERR, "sprintaddr:getnameinfo: %s\n", gai_strerror(res)); @@ -469,26 +461,16 @@ char* sprintaddr(char* buf, size_t size, struct addrinfo *a) /* Turns a hostname and port (or service) into a list of struct addrinfo * returns 0 on success, -1 otherwise and logs error */ -int resolve_split_name(struct addrinfo **out, const char* ct_host, const char* serv) +int resolve_split_name(struct addrinfo **out, char* host, char* serv) { struct addrinfo hint; char *end; int res; - char* host, *host_base; memset(&hint, 0, sizeof(hint)); hint.ai_family = PF_UNSPEC; hint.ai_socktype = SOCK_STREAM; - /* Copy parameter so not to clobber data in libconfig */ - res = asprintf(&host_base, "%s", ct_host); - if (res == -1) { - log_message(LOG_ERR, "asprintf: cannot allocate memory"); - return -1; - } - - host = host_base; - /* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets * around IP address */ if (host[0] == '[') { @@ -504,7 +486,6 @@ int resolve_split_name(struct addrinfo **out, const char* ct_host, const char* s res = getaddrinfo(host, serv, &hint, out); if (res) log_message(LOG_ERR, "%s `%s:%s'\n", gai_strerror(res), host, serv); - free(host_base); return res; } @@ -543,7 +524,7 @@ void log_message(int type, char* msg, ...) va_list ap; va_start(ap, msg); - if (foreground) + if (cfg.foreground) vfprintf(stderr, msg, ap); else vsyslog(type, msg, ap); @@ -587,7 +568,7 @@ void log_connection(struct connection *cnx) sprintaddr(local, sizeof(local), &addr); log_message(LOG_INFO, "%s:connection from %s to %s forwarded from %s to %s\n", - cnx->proto->description, + cnx->proto->name, peer, service, local, @@ -618,22 +599,22 @@ int check_access_rights(int in_socket, const char* service) /* extract peer address */ res = getnameinfo(&peer.saddr, size, addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST); if (res) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "getnameinfo(NI_NUMERICHOST):%s\n", gai_strerror(res)); strcpy(addr_str, STRING_UNKNOWN); } /* extract peer name */ strcpy(host, STRING_UNKNOWN); - if (!numeric) { + if (!cfg.numeric) { res = getnameinfo(&peer.saddr, size, host, sizeof(host), NULL, 0, NI_NAMEREQD); if (res) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "getnameinfo(NI_NAMEREQD):%s\n", gai_strerror(res)); } } if (!hosts_ctl(service, host, addr_str, STRING_UNKNOWN)) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "access denied\n"); log_message(LOG_INFO, "connection from %s(%s): access denied", host, addr_str); close(in_socket); @@ -681,10 +662,10 @@ void setup_syslog(const char* bin_name) { CHECK_RES_DIE(res, "asprintf"); for (fn = 0; facilitynames[fn].c_val != -1; fn++) - if (strcmp(facilitynames[fn].c_name, facility) == 0) + if (strcmp(facilitynames[fn].c_name, cfg.syslog_facility) == 0) break; if (facilitynames[fn].c_val == -1) { - fprintf(stderr, "Unknown facility %s\n", facility); + fprintf(stderr, "Unknown facility %s\n", cfg.syslog_facility); exit(1); } @@ -715,7 +696,7 @@ void set_capabilities(void) { cap_value_t cap_list[10]; int ncap = 0; - if (transparent) + if (cfg.transparent) cap_list[ncap++] = CAP_NET_ADMIN; caps = cap_init(); @@ -757,12 +738,12 @@ void drop_privileges(const char* user_name, const char* chroot_path) fprintf(stderr, "%s: not found\n", user_name); exit(2); } - if (verbose) + if (cfg.verbose) fprintf(stderr, "turning into %s\n", user_name); } if (chroot_path) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "chrooting into %s\n", chroot_path); res = chroot(chroot_path); diff --git a/common.h b/common.h index e8fad3e..a6478e5 100644 --- a/common.h +++ b/common.h @@ -87,7 +87,7 @@ struct queue { struct connection { enum connection_state state; time_t probe_timeout; - struct proto *proto; + struct config_protocols_item* proto; /* q[0]: queue for external connection (client); * q[1]: queue for internal connection (httpd or sshd); @@ -114,7 +114,7 @@ void drop_privileges(const char* user_name, const char* chroot_path); void write_pid_file(const char* pidfile); void log_message(int type, char* msg, ...); void dump_connection(struct connection *cnx); -int resolve_split_name(struct addrinfo **out, const char* hostname, const char* port); +int resolve_split_name(struct addrinfo **out, char* hostname, char* port); int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list); @@ -123,6 +123,7 @@ int flush_deferred(struct queue *q); extern int probing_timeout, verbose, inetd, foreground, background, transparent, numeric; +extern struct config_item cfg; extern struct sockaddr_storage addr_ssl, addr_ssh, addr_openvpn; extern struct addrinfo *addr_listen; extern const char* USAGE_STRING; diff --git a/echosrv.c b/echosrv.c index 65a85c3..e5838d2 100644 --- a/echosrv.c +++ b/echosrv.c @@ -53,6 +53,8 @@ const char* server_type = "echsrv"; /* keep setup_syslog happy */ char* prefix = ""; int port; +int verbose, numeric; + void parse_cmdline(int argc, char* argv[]) { int c; diff --git a/example.cfg b/example.cfg index 182f508..dc9e650 100644 --- a/example.cfg +++ b/example.cfg @@ -66,7 +66,10 @@ listen: protocols: ( - { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; keepalive: true; fork: true; }, + { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; keepalive: true; fork: true; +listen: ( { host: "hello"; port: "xmpp" }, { host: "world"; +port: "dns" } ), + }, { name: "http"; host: "localhost"; port: "80"; }, # match BOTH ALPN/SNI diff --git a/probe.c b/probe.c index 15ff8b9..6c280c0 100644 --- a/probe.c +++ b/probe.c @@ -33,36 +33,43 @@ -static int is_ssh_protocol(const char *p, int len, struct proto*); -static int is_openvpn_protocol(const char *p, int len, struct proto*); -static int is_tinc_protocol(const char *p, int len, struct proto*); -static int is_xmpp_protocol(const char *p, int len, struct proto*); -static int is_http_protocol(const char *p, int len, struct proto*); -static int is_tls_protocol(const char *p, int len, struct proto*); -static int is_adb_protocol(const char *p, int len, struct proto*); -static int is_socks5_protocol(const char *p, int len, struct proto*); -static int is_true(const char *p, int len, struct proto* proto) { return 1; } +static int is_ssh_protocol(const char *p, int len, struct config_protocols_item*); +static int is_openvpn_protocol(const char *p, int len, struct config_protocols_item*); +static int is_tinc_protocol(const char *p, int len, struct config_protocols_item*); +static int is_xmpp_protocol(const char *p, int len, struct config_protocols_item*); +static int is_http_protocol(const char *p, int len, struct config_protocols_item*); +static int is_tls_protocol(const char *p, int len, struct config_protocols_item*); +static int is_adb_protocol(const char *p, int len, struct config_protocols_item*); +static int is_socks5_protocol(const char *p, int len, struct config_protocols_item*); +static int is_true(const char *p, int len, struct config_protocols_item* proto) { return 1; } + +struct protocol_probe_desc { + const char* name; + T_PROBE* probe; +}; /* Table of protocols that have a built-in probe */ -static struct proto builtins[] = { - /* description service saddr log_level keepalive fork probe */ - { "ssh", "sshd", NULL, 1, 0, 1, is_ssh_protocol}, - { "openvpn", NULL, NULL, 1, 0, 1, is_openvpn_protocol }, - { "tinc", NULL, NULL, 1, 0, 1, is_tinc_protocol }, - { "xmpp", NULL, NULL, 1, 0, 0, is_xmpp_protocol }, - { "http", NULL, NULL, 1, 0, 0, is_http_protocol }, - { "tls", NULL, NULL, 1, 0, 0, is_tls_protocol }, - { "adb", NULL, NULL, 1, 0, 0, is_adb_protocol }, - { "socks5", NULL, NULL, 1, 0, 0, is_socks5_protocol }, - { "anyprot", NULL, NULL, 1, 0, 0, is_true } +static struct protocol_probe_desc builtins[] = { + /* description probe */ + { "ssh", is_ssh_protocol}, + { "openvpn", is_openvpn_protocol }, + { "tinc", is_tinc_protocol }, + { "xmpp", is_xmpp_protocol }, + { "http", is_http_protocol }, + { "tls", is_tls_protocol }, + { "ssl", is_tls_protocol }, + { "adb", is_adb_protocol }, + { "socks5", is_socks5_protocol }, + { "anyprot", is_true } }; -static struct proto *protocols; +static struct config_protocols_item *protocols; static char* on_timeout = "ssh"; -struct proto* get_builtins(void) { - return builtins; +/* TODO I think this has to go */ +struct config_protocols_item* get_builtins(void) { + return NULL; } int get_num_builtins(void) { @@ -79,23 +86,27 @@ void set_ontimeout(const char* name) /* Returns the protocol to connect to in case of timeout; * if not found, return the first protocol specified */ -struct proto* timeout_protocol(void) +struct config_protocols_item* timeout_protocol(void) { - struct proto* p = get_first_protocol(); - for (; p && strcmp(p->description, on_timeout); p = p->next); - if (p) return p; + int i; + for (i = 0; i < cfg.protocols_len; i++) { + printf("prot %d:%s vs %s\n",i, cfg.protocols[i].name, on_timeout); + if (!strcmp(cfg.protocols[i].name, on_timeout)) return &cfg.protocols[i]; + } return get_first_protocol(); } /* returns the first protocol (caller can then follow the *next pointers) */ -struct proto* get_first_protocol(void) +struct config_protocols_item* get_first_protocol(void) { return protocols; } -void set_protocol_list(struct proto* prots) +void set_protocol_list(struct config_protocols_item* prots) { +#if 0 protocols = prots; +#endif } /* From http://grapsus.net/blog/post/Hexadecimal-dump-in-C */ @@ -132,7 +143,7 @@ void hexdump(const char *mem, unsigned int len) } /* Is the buffer the beginning of an SSH connection? */ -static int is_ssh_protocol(const char *p, int len, struct proto *proto) +static int is_ssh_protocol(const char *p, int len, struct config_protocols_item* proto) { if (len < 4) return PROBE_AGAIN; @@ -150,7 +161,7 @@ static int is_ssh_protocol(const char *p, int len, struct proto *proto) * http://www.fengnet.com/book/vpns%20illustrated%20tunnels%20%20vpnsand%20ipsec/ch08lev1sec5.html * and OpenVPN ssl.c, ssl.h and options.c */ -static int is_openvpn_protocol (const char*p,int len, struct proto *proto) +static int is_openvpn_protocol (const char*p,int len, struct config_protocols_item* proto) { int packet_len; @@ -165,7 +176,7 @@ static int is_openvpn_protocol (const char*p,int len, struct proto *proto) * Protocol is documented here: http://www.tinc-vpn.org/documentation/tinc.pdf * First connection starts with "0 " in 1.0.15) * */ -static int is_tinc_protocol( const char *p, int len, struct proto *proto) +static int is_tinc_protocol( const char *p, int len, struct config_protocols_item* proto) { if (len < 2) return PROBE_AGAIN; @@ -177,7 +188,7 @@ static int is_tinc_protocol( const char *p, int len, struct proto *proto) * (Protocol is documented (http://tools.ietf.org/html/rfc6120) but for lazy * clients, just checking first frame containing "jabber" in xml entity) * */ -static int is_xmpp_protocol( const char *p, int len, struct proto *proto) +static int is_xmpp_protocol( const char *p, int len, struct config_protocols_item* proto) { if (memmem(p, len, "jabber", 6)) return PROBE_MATCH; @@ -200,7 +211,7 @@ static int probe_http_method(const char *p, int len, const char *opt) } /* Is the buffer the beginning of an HTTP connection? */ -static int is_http_protocol(const char *p, int len, struct proto *proto) +static int is_http_protocol(const char *p, int len, struct config_protocols_item* proto) { int res; /* If it's got HTTP in the request (HTTP/1.1) then it's HTTP */ @@ -226,7 +237,7 @@ static int is_http_protocol(const char *p, int len, struct proto *proto) } /* Says if it's TLS, optionally with SNI and ALPN lists in proto->data */ -static int is_tls_protocol(const char *p, int len, struct proto *proto) +static int is_tls_protocol(const char *p, int len, struct config_protocols_item* proto) { switch (parse_tls_header(proto->data, p, len)) { case TLS_MATCH: return PROBE_MATCH; @@ -246,7 +257,7 @@ static int probe_adb_cnxn_message(const char *p) return !memcmp(&p[0], "CNXN", 4) && !memcmp(&p[24], "host:", 5); } -static int is_adb_protocol(const char *p, int len, struct proto *proto) +static int is_adb_protocol(const char *p, int len, struct config_protocols_item* proto) { /* amessage.data_length is not being checked, under the assumption that * a packet >= 30 bytes will have "something" in the payload field. @@ -285,7 +296,7 @@ static int is_adb_protocol(const char *p, int len, struct proto *proto) return probe_adb_cnxn_message(&p[sizeof(empty_message)]); } -static int is_socks5_protocol(const char *p_in, int len, struct proto *proto) +static int is_socks5_protocol(const char *p_in, int len, struct config_protocols_item* proto) { unsigned char* p = (unsigned char*)p_in; int i; @@ -318,7 +329,7 @@ static int is_socks5_protocol(const char *p_in, int len, struct proto *proto) return PROBE_MATCH; } -static int regex_probe(const char *p, int len, struct proto *proto) +static int regex_probe(const char *p, int len, struct config_protocols_item* proto) { #ifdef ENABLE_REGEX regex_t **probe = proto->data; @@ -344,8 +355,8 @@ static int regex_probe(const char *p, int len, struct proto *proto) int probe_client_protocol(struct connection *cnx) { char buffer[BUFSIZ]; - struct proto *p, *last_p = cnx->proto; - int n, res, again = 0; + struct config_protocols_item* p, *last_p = cnx->proto; + int i, n, res, again = 0; n = read(cnx->q[0].fd, buffer, sizeof(buffer)); /* It's possible that read() returns an error, e.g. if the client @@ -355,26 +366,26 @@ int probe_client_protocol(struct connection *cnx) * connection will just fail later normally). */ if (n > 0) { - if (verbose > 1) { + if (cfg.verbose > 1) { fprintf(stderr, "hexdump of incoming packet:\n"); hexdump(buffer, n); } defer_write(&cnx->q[1], buffer, n); } - for (p = cnx->proto; p; p = p->next) { + for (i = 0; i < cfg.protocols_len; i++) { char* probe_str[3] = {"PROBE_NEXT", "PROBE_MATCH", "PROBE_AGAIN"}; + p = &cfg.protocols[i]; + if (! p->probe) continue; /* Don't probe last protocol if it is anyprot (and store last protocol) */ - if (! p->next) { - last_p = p; - if (!strcmp(p->description, "anyprot")) - break; - } + if ((i == cfg.protocols_len - 1) && (!strcmp(p->name, "anyprot"))) + break; + if (cfg.verbose) fprintf(stderr, "probing for %s\n", p->name); res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p); - if (verbose) fprintf(stderr, "probing for %s: %s\n", p->description, probe_str[res]); + if (cfg.verbose) fprintf(stderr, "probed for %s: %s\n", p->name, probe_str[res]); if (res == PROBE_MATCH) { cnx->proto = p; @@ -387,31 +398,21 @@ int probe_client_protocol(struct connection *cnx) return PROBE_AGAIN; /* Everything failed: match the last one */ - cnx->proto = last_p; + cnx->proto = &cfg.protocols[cfg.protocols_len-1]; return PROBE_MATCH; } -/* Returns the structure for specified protocol or NULL if not found */ -static struct proto* get_protocol(const char* description) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(builtins); i++) { - if (!strcmp(builtins[i].description, description)) { - return &builtins[i]; - } - } - return NULL; -} - /* Returns the probe for specified protocol: * parameter is the description in builtins[], or "regex" * */ T_PROBE* get_probe(const char* description) { - struct proto* p = get_protocol(description); + int i; - if (p) - return p->probe; + for (i = 0; i < ARRAY_SIZE(builtins); i++) { + if (!strcmp(builtins[i].name, description)) { + return builtins[i].probe; + } + } /* Special case of "regex" probe (we don't want to set it in builtins * because builtins is also used to build the command-line options and diff --git a/probe.h b/probe.h index 2476542..0e465f9 100644 --- a/probe.h +++ b/probe.h @@ -12,10 +12,13 @@ typedef enum { PROBE_AGAIN, /* Not enough data for this probe, try again with more data */ } probe_result; -struct proto; -typedef int T_PROBE(const char*, int, struct proto*); +struct config_protocols_item; +typedef int T_PROBE(const char*, int, struct config_protocols_item*); + +#include "sslh-conf.h" /* For each protocol we need: */ +#if 0 struct proto { const char* description; /* a string that says what it is (for logging and command-line parsing) */ const char* service; /* service name to do libwrap checks */ @@ -33,9 +36,10 @@ struct proto { void* data; struct proto *next; /* pointer to next protocol in list, NULL if last */ }; +#endif /* Returns a pointer to the array of builtin protocols */ -struct proto * get_builtins(void); +struct config_protocols_item* get_builtins(void); /* Returns the number of builtin protocols */ int get_num_builtins(void); @@ -44,10 +48,10 @@ int get_num_builtins(void); T_PROBE* get_probe(const char* description); /* Returns the head of the configured protocols */ -struct proto* get_first_protocol(void); +struct config_protocols_item* get_first_protocol(void); /* Set the list of configured protocols */ -void set_protocol_list(struct proto*); +void set_protocol_list(struct config_protocols_item*); /* probe_client_protocol * @@ -65,7 +69,7 @@ void set_ontimeout(const char* name); * * Returns the protocol to connect to in case of timeout */ -struct proto* timeout_protocol(void); +struct config_protocols_item* timeout_protocol(void); void hexdump(const char*, unsigned int); diff --git a/sslh-conf.c b/sslh-conf.c index 2d59e99..df022e5 100644 --- a/sslh-conf.c +++ b/sslh-conf.c @@ -1,8 +1,9 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct) - * on Thu Nov 22 17:16:04 2018. */ + * on Wed Nov 28 23:38:56 2018. */ +#define _GNU_SOURCE #include #include #include @@ -10,10 +11,11 @@ static int config_protocols_parser( config_setting_t* cfg, - struct config_protocols_items* config_protocols, + struct config_protocols_item* config_protocols, const char** errmsg) { config_setting_t* setting; + char* tmp; *errmsg = NULL; if (config_setting_lookup(cfg, "name")) { @@ -34,6 +36,11 @@ static int config_protocols_parser( *errmsg = "Mandatory option \"host\" is missing"; return 0; } + if (asprintf(&tmp, "%s", config_protocols->host) == -1) { + *errmsg = "asprintf: cannot allocate memory"; + return 0; + } + config_protocols->host = tmp; if (config_setting_lookup(cfg, "port")) { if (config_setting_lookup_string(cfg, "port", &config_protocols->port) == CONFIG_FALSE) { *errmsg = "Parsing of option \"port\" failed"; @@ -43,10 +50,15 @@ static int config_protocols_parser( *errmsg = "Mandatory option \"port\" is missing"; return 0; } + if (asprintf(&tmp, "%s", config_protocols->port) == -1) { + *errmsg = "asprintf: cannot allocate memory"; + return 0; + } + config_protocols->port = tmp; config_protocols->service = NULL; if (config_setting_lookup(cfg, "service")) { if (config_setting_lookup_string(cfg, "service", &config_protocols->service) == CONFIG_FALSE) { - *errmsg = "Parsing of option service failed"; + *errmsg = "Parsing of option \"service\" failed"; return 0; } else { config_protocols->service_is_present = 1; @@ -56,21 +68,21 @@ static int config_protocols_parser( config_protocols->fork = 0; if (config_setting_lookup(cfg, "fork")) { if (config_setting_lookup_bool(cfg, "fork", &config_protocols->fork) == CONFIG_FALSE) { - *errmsg = "Parsing of option fork failed"; + *errmsg = "Parsing of option \"fork\" failed"; return 0; } ; } config_protocols->log_level = 1; if (config_setting_lookup(cfg, "log_level")) { if (config_setting_lookup_int(cfg, "log_level", &config_protocols->log_level) == CONFIG_FALSE) { - *errmsg = "Parsing of option log_level failed"; + *errmsg = "Parsing of option \"log_level\" failed"; return 0; } ; } config_protocols->keepalive = 0; if (config_setting_lookup(cfg, "keepalive")) { if (config_setting_lookup_bool(cfg, "keepalive", &config_protocols->keepalive) == CONFIG_FALSE) { - *errmsg = "Parsing of option keepalive failed"; + *errmsg = "Parsing of option \"keepalive\" failed"; return 0; } ; } @@ -112,10 +124,11 @@ static int config_protocols_parser( static int config_listen_parser( config_setting_t* cfg, - struct config_listen_items* config_listen, + struct config_listen_item* config_listen, const char** errmsg) { config_setting_t* setting; + char* tmp; *errmsg = NULL; if (config_setting_lookup(cfg, "host")) { @@ -127,6 +140,11 @@ static int config_listen_parser( *errmsg = "Mandatory option \"host\" is missing"; return 0; } + if (asprintf(&tmp, "%s", config_listen->host) == -1) { + *errmsg = "asprintf: cannot allocate memory"; + return 0; + } + config_listen->host = tmp; if (config_setting_lookup(cfg, "port")) { if (config_setting_lookup_string(cfg, "port", &config_listen->port) == CONFIG_FALSE) { *errmsg = "Parsing of option \"port\" failed"; @@ -136,10 +154,15 @@ static int config_listen_parser( *errmsg = "Mandatory option \"port\" is missing"; return 0; } + if (asprintf(&tmp, "%s", config_listen->port) == -1) { + *errmsg = "asprintf: cannot allocate memory"; + return 0; + } + config_listen->port = tmp; config_listen->keepalive = 0; if (config_setting_lookup(cfg, "keepalive")) { if (config_setting_lookup_bool(cfg, "keepalive", &config_listen->keepalive) == CONFIG_FALSE) { - *errmsg = "Parsing of option keepalive failed"; + *errmsg = "Parsing of option \"keepalive\" failed"; return 0; } ; } @@ -148,58 +171,59 @@ static int config_listen_parser( int config_parser( config_setting_t* cfg, - struct config_items* config, + struct config_item* config, const char** errmsg) { config_setting_t* setting; + char* tmp; *errmsg = NULL; config->verbose = 0; if (config_setting_lookup(cfg, "verbose")) { - if (config_setting_lookup_bool(cfg, "verbose", &config->verbose) == CONFIG_FALSE) { - *errmsg = "Parsing of option verbose failed"; + if (config_setting_lookup_int(cfg, "verbose", &config->verbose) == CONFIG_FALSE) { + *errmsg = "Parsing of option \"verbose\" failed"; return 0; } ; } config->foreground = 0; if (config_setting_lookup(cfg, "foreground")) { if (config_setting_lookup_bool(cfg, "foreground", &config->foreground) == CONFIG_FALSE) { - *errmsg = "Parsing of option foreground failed"; + *errmsg = "Parsing of option \"foreground\" failed"; return 0; } ; } config->inetd = 0; if (config_setting_lookup(cfg, "inetd")) { if (config_setting_lookup_bool(cfg, "inetd", &config->inetd) == CONFIG_FALSE) { - *errmsg = "Parsing of option inetd failed"; + *errmsg = "Parsing of option \"inetd\" failed"; return 0; } ; } config->numeric = 0; if (config_setting_lookup(cfg, "numeric")) { if (config_setting_lookup_bool(cfg, "numeric", &config->numeric) == CONFIG_FALSE) { - *errmsg = "Parsing of option numeric failed"; + *errmsg = "Parsing of option \"numeric\" failed"; return 0; } ; } config->transparent = 0; if (config_setting_lookup(cfg, "transparent")) { if (config_setting_lookup_bool(cfg, "transparent", &config->transparent) == CONFIG_FALSE) { - *errmsg = "Parsing of option transparent failed"; + *errmsg = "Parsing of option \"transparent\" failed"; return 0; } ; } config->timeout = 2; if (config_setting_lookup(cfg, "timeout")) { if (config_setting_lookup_int(cfg, "timeout", &config->timeout) == CONFIG_FALSE) { - *errmsg = "Parsing of option timeout failed"; + *errmsg = "Parsing of option \"timeout\" failed"; return 0; } ; } config->user = NULL; if (config_setting_lookup(cfg, "user")) { if (config_setting_lookup_string(cfg, "user", &config->user) == CONFIG_FALSE) { - *errmsg = "Parsing of option user failed"; + *errmsg = "Parsing of option \"user\" failed"; return 0; } else { config->user_is_present = 1; @@ -209,33 +233,34 @@ int config_parser( config->pidfile = NULL; if (config_setting_lookup(cfg, "pidfile")) { if (config_setting_lookup_string(cfg, "pidfile", &config->pidfile) == CONFIG_FALSE) { - *errmsg = "Parsing of option pidfile failed"; + *errmsg = "Parsing of option \"pidfile\" failed"; return 0; } else { config->pidfile_is_present = 1; } ; } + config->chroot = NULL; if (config_setting_lookup(cfg, "chroot")) { if (config_setting_lookup_string(cfg, "chroot", &config->chroot) == CONFIG_FALSE) { *errmsg = "Parsing of option \"chroot\" failed"; return 0; - } - } else { - *errmsg = "Mandatory option \"chroot\" is missing"; - return 0; + } else { + config->chroot_is_present = 1; + } +; } config->syslog_facility = "auth"; if (config_setting_lookup(cfg, "syslog_facility")) { if (config_setting_lookup_string(cfg, "syslog_facility", &config->syslog_facility) == CONFIG_FALSE) { - *errmsg = "Parsing of option syslog_facility failed"; + *errmsg = "Parsing of option \"syslog_facility\" failed"; return 0; } ; } config->on_timeout = "ssh"; if (config_setting_lookup(cfg, "on_timeout")) { if (config_setting_lookup_string(cfg, "on_timeout", &config->on_timeout) == CONFIG_FALSE) { - *errmsg = "Parsing of option on_timeout failed"; + *errmsg = "Parsing of option \"on_timeout\" failed"; return 0; } ; } @@ -276,7 +301,7 @@ static void indent(int depth) } static void config_protocols_print( - struct config_protocols_items* config_protocols, + struct config_protocols_item* config_protocols, int depth) { int i; @@ -316,7 +341,7 @@ static void config_protocols_print( } static void config_listen_print( - struct config_listen_items* config_listen, + struct config_listen_item* config_listen, int depth) { int i; @@ -330,7 +355,7 @@ static void config_listen_print( } void config_print( - struct config_items* config, + struct config_item* config, int depth) { int i; diff --git a/sslh-conf.h b/sslh-conf.h index a7af686..8cf787a 100644 --- a/sslh-conf.h +++ b/sslh-conf.h @@ -1,10 +1,26 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct) - * on Thu Nov 22 17:16:04 2018. */ + * on Wed Nov 28 23:38:56 2018. */ -struct config_protocols_items { + +#ifndef C2S_CONFIG_H +#define C2S_CONFIG_H +#include + +#include "probe.h" +#include +#include +#include + +struct config_listen_item { + char* host; + char* port; + int keepalive; +}; + +struct config_protocols_item { const char* name; - const char* host; - const char* port; + char* host; + char* port; int service_is_present; const char* service; int fork; @@ -16,17 +32,12 @@ struct config_protocols_items { const char** alpn_protocols; int regex_patterns_len; const char** regex_patterns; + T_PROBE* probe; + struct addrinfo* saddr; + void* data; }; - -struct config_listen_items { - const char* host; - const char* port; - int keepalive; -}; - - -struct config_items { +struct config_item { int verbose; int foreground; int inetd; @@ -37,20 +48,23 @@ struct config_items { const char* user; int pidfile_is_present; const char* pidfile; + int chroot_is_present; const char* chroot; const char* syslog_facility; const char* on_timeout; int listen_len; - struct config_listen_items* listen; + struct config_listen_item* listen; int protocols_len; - struct config_protocols_items* protocols; + struct config_protocols_item* protocols; }; int config_parser( config_setting_t* cfg, - struct config_items* config, + struct config_item* config, const char** errmsg); void config_print( - struct config_items *config, + struct config_item *config, int depth); + +#endif diff --git a/sslh-fork.c b/sslh-fork.c index 78bf460..164be80 100644 --- a/sslh-fork.c +++ b/sslh-fork.c @@ -54,7 +54,7 @@ int shovel(struct connection *cnx) if (FD_ISSET(cnx->q[i].fd, &fds)) { res = fd2fd(&cnx->q[1-i], &cnx->q[i]); if (!res) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "%s %s", i ? "client" : "server", "socket closed\n"); return res; } @@ -79,7 +79,7 @@ void start_shoveler(int in_socket) FD_ZERO(&fds); FD_SET(in_socket, &fds); memset(&tv, 0, sizeof(tv)); - tv.tv_sec = probing_timeout; + tv.tv_sec = cfg.timeout; while (res == PROBE_AGAIN) { /* POSIX does not guarantee that tv will be updated, but the client can @@ -94,8 +94,8 @@ void start_shoveler(int in_socket) } else { /* Timed out: it's necessarily SSH */ cnx.proto = timeout_protocol(); - if (verbose) - log_message(LOG_INFO, "timed out, connect to %s\n", cnx.proto->description); + if (cfg.verbose) + log_message(LOG_INFO, "timed out, connect to %s\n", cnx.proto->name); break; } } @@ -120,7 +120,7 @@ void start_shoveler(int in_socket) close(in_socket); close(out_socket); - if (verbose) + if (cfg.verbose) fprintf(stderr, "connection closed down\n"); exit(0); @@ -161,7 +161,7 @@ void main_loop(int listen_sockets[], int num_addr_listen) while (1) { in_socket = accept(listen_sockets[i], 0, 0); - if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket); + if (cfg.verbose) fprintf(stderr, "accepted fd %d\n", in_socket); switch(fork()) { case -1: log_message(LOG_ERR, "fork failed: err %d: %s\n", errno, strerror(errno)); diff --git a/sslh-main.c b/sslh-main.c index aaadc74..9a8543e 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -2,7 +2,7 @@ # main: processing of config file, command line options and start the main # loop. # -# Copyright (C) 2007-2016 Yves Rutschle +# Copyright (C) 2007-2018 Yves Rutschle # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General Public @@ -62,6 +62,7 @@ const char* USAGE_STRING = /* Constants for options that have no one-character shorthand */ #define OPT_ONTIMEOUT 257 + /* static struct option const_options[] = { { "inetd", no_argument, &inetd, 1 }, { "foreground", no_argument, &foreground, 1 }, @@ -78,22 +79,25 @@ static struct option const_options[] = { { "listen", required_argument, 0, 'p' }, {} }; + */ static struct option* all_options; -static struct proto* builtins; +#if 0 +static struct config_protocols_item* builtins; +#endif static const char *optstr = "vt:T:p:VP:C:F::"; static void print_usage(void) { - struct proto *p; + struct config_protocols_item *p; int i; int res; char *prots = ""; p = get_builtins(); for (i = 0; i < get_num_builtins(); i++) { - res = asprintf(&prots, "%s\t[--%s ]\n", prots, p[i].description); + res = asprintf(&prots, "%s\t[--%s ]\n", prots, p[i].name); CHECK_RES_DIE(res, "asprintf"); } @@ -121,12 +125,14 @@ static void printsettings(void) { char buf[NI_MAXHOST]; struct addrinfo *a; - struct proto *p; + int i; + struct config_protocols_item *p; - for (p = get_first_protocol(); p; p = p->next) { + for (i = 0; i < cfg.protocols_len; i++ ) { + p = &cfg.protocols[i]; fprintf(stderr, "%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s] [%s]\n", - p->description, + p->name, sprintaddr(buf, sizeof(buf), p->saddr), p->service, p->log_level, @@ -142,8 +148,8 @@ static void printsettings(void) sprintaddr(buf, sizeof(buf), a), a->ai_flags & SO_KEEPALIVE ? "keepalive" : ""); } - fprintf(stderr, "timeout: %d\non-timeout: %s\n", probing_timeout, - timeout_protocol()->description); + fprintf(stderr, "timeout: %d\non-timeout: %s\n", cfg.timeout, + timeout_protocol()->name); } @@ -177,6 +183,26 @@ void cmd_ssl_to_tls(int argc, char* argv[]) * out: newly allocated list of addrinfo to listen to */ #ifdef LIBCONFIG +static int config_resolve_listen(struct addrinfo **listen) +{ + int i; + for (i = 0; i < cfg.listen_len; i++) { + resolve_split_name(listen, cfg.listen[i].host, cfg.listen[i].port); + + /* getaddrinfo returned a list of addresses corresponding to the + * specification; move the pointer to the end of that list before + * processing the next specification, while setting flags for + * start_listen_sockets() through ai_flags (which is not meant for + * that, but is only used as hint in getaddrinfo, so it's OK) */ + for (; *listen; listen = &((*listen)->ai_next)) { + if (cfg.listen[i].keepalive) + (*listen)->ai_flags = SO_KEEPALIVE; + } + } + return 0; +} + +#if 0 static int config_listen(config_t *config, struct addrinfo **listen) { config_setting_t *setting, *addr; @@ -216,11 +242,12 @@ static int config_listen(config_t *config, struct addrinfo **listen) return 0; } #endif +#endif #ifdef LIBCONFIG -static void setup_regex_probe(struct proto *p, config_setting_t* probes) +static void setup_regex_probe(struct config_protocols_item *p, config_setting_t* probes) { #ifdef ENABLE_REGEX int num_probes, errsize, i, res; @@ -230,7 +257,7 @@ static void setup_regex_probe(struct proto *p, config_setting_t* probes) num_probes = config_setting_length(probes); if (!num_probes) { - fprintf(stderr, "%s: no probes specified\n", p->description); + fprintf(stderr, "%s: no probes specified\n", p->name); exit(1); } @@ -244,7 +271,7 @@ static void setup_regex_probe(struct proto *p, config_setting_t* probes) CHECK_ALLOC(probe_list[i], "malloc"); expr = config_setting_get_string_elem(probes, i); if (expr == NULL) { - fprintf(stderr, "%s: invalid probe specified\n", p->description); + fprintf(stderr, "%s: invalid probe specified\n", p->name); exit(1); } res = regcomp(probe_list[i], expr, REG_EXTENDED); @@ -265,7 +292,12 @@ static void setup_regex_probe(struct proto *p, config_setting_t* probes) #endif #ifdef LIBCONFIG -static void setup_sni_alpn_list(struct proto *p, config_setting_t* config_items, const char* name, int alpn) +#if 0 +static void setup_sni_alpn_list( + struct config_protocols_item *p, + config_setting_t* config_items, + const char* name, + int alpn) { int num_probes, i, max_server_name_len, server_name_len; const char * config_item, *server_name; @@ -307,7 +339,7 @@ static void setup_sni_alpn_list(struct proto *p, config_setting_t* config_items, p->data = (void*)tls_data_set_list(p->data, alpn, sni_hostname_list); } -static void setup_sni_alpn(struct proto *p, config_setting_t* prot) +static void setup_sni_alpn(struct config_protocols_item *p, config_setting_t* prot) { config_setting_t *sni_hostnames, *alpn_protocols; @@ -323,11 +355,45 @@ static void setup_sni_alpn(struct proto *p, config_setting_t* prot) } } #endif +static void setup_sni_alpn(struct config_protocols_item *p, config_setting_t* prot) +{} +#endif -/* Extract configuration for protocols to connect to. - * out: newly-allocated list of protocols +/* For each protocol in the configuration, resolve address and set up protocol + * options if required */ #ifdef LIBCONFIG +static int config_protocols() +{ + int i; + for (i = 0; i < cfg.protocols_len; i++) { + struct config_protocols_item* p = &(cfg.protocols[i]); + if (resolve_split_name(&(p->saddr), p->host, p->port)) { + fprintf(stderr, "cannot resolve %s:%s\n", p->host, p->port); + exit(1); + } + + p->probe = get_probe(p->name); + if (!p->probe) { + fprintf(stderr, "%s: probe unknown\n", p->name); + exit(1); + } + + if (!strcmp(cfg.protocols[i].name, "tls")) { + cfg.protocols[i].data = (void*)new_tls_data(); + if (cfg.protocols[i].sni_hostnames_len) + tls_data_set_list(cfg.protocols[i].data, 0, + cfg.protocols[i].sni_hostnames, + cfg.protocols[i].sni_hostnames_len); + if (cfg.protocols[i].alpn_protocols_len) + tls_data_set_list(cfg.protocols[i].data, 1, + cfg.protocols[i].alpn_protocols, + cfg.protocols[i].alpn_protocols_len); + } + } +} + +#if 0 static int config_protocols(config_t *config, struct proto **prots) { config_setting_t *setting, *prot, *patterns; @@ -398,6 +464,7 @@ static int config_protocols(config_t *config, struct proto **prots) return 0; } #endif +#endif /* Parses a config file * in: *filename @@ -406,11 +473,11 @@ static int config_protocols(config_t *config, struct proto **prots) * 1 on error, 0 on success */ #ifdef LIBCONFIG -static int config_parse(char *filename, struct addrinfo **listen, struct proto **prots) +static int config_parse(char *filename, struct addrinfo **listen, struct config_protocols_item **prots) { config_t config; - int timeout; - const char* str; + int res; + const char*err; config_init(&config); if (config_read_file(&config, filename) == CONFIG_FALSE) { @@ -429,32 +496,19 @@ static int config_parse(char *filename, struct addrinfo **listen, struct proto * config_error_text(&config)); return 1; } - - if(config_lookup_bool(&config, "verbose", &verbose) == CONFIG_FALSE) { - config_lookup_int(&config, "verbose", &verbose); + res = config_parser(config_lookup(&config, "/"), &cfg, &err); + if (!res) { + fprintf(stderr, "%s\n", err); + exit(1); } - config_lookup_bool(&config, "inetd", &inetd); - config_lookup_bool(&config, "foreground", &foreground); - config_lookup_bool(&config, "numeric", &numeric); - config_lookup_bool(&config, "transparent", &transparent); - - if (config_lookup_int(&config, "timeout", (int *)&timeout) == CONFIG_TRUE) { - probing_timeout = timeout; - } - - if (config_lookup_string(&config, "on-timeout", &str)) { - set_ontimeout(str); - } - - config_lookup_string(&config, "user", &user_name); - config_lookup_string(&config, "pidfile", &pid_file); - config_lookup_string(&config, "chroot", &chroot_path); - - config_lookup_string(&config, "syslog_facility", &facility); + config_resolve_listen(listen); + config_protocols(); + /* config_listen(&config, listen); config_protocols(&config, prots); + */ return 0; } @@ -467,12 +521,12 @@ static int config_parse(char *filename, struct addrinfo **listen, struct proto * * prot: array of protocols * n_prots: number of protocols in *prot * */ -static void append_protocols(struct option *options, int n_opts, struct proto *prot , int n_prots) +static void append_protocols(struct option *options, int n_opts, struct config_protocols_item *prot , int n_prots) { int o, p; for (o = n_opts, p = 0; p < n_prots; o++, p++) { - options[o].name = prot[p].description; + options[o].name = prot[p].name; options[o].has_arg = required_argument; options[o].flag = 0; options[o].val = p + PROT_SHIFT; @@ -481,6 +535,7 @@ static void append_protocols(struct option *options, int n_opts, struct proto *p static void make_alloptions(void) { +#if 0 builtins = get_builtins(); /* Create all_options, composed of const_options followed by one option per @@ -489,6 +544,7 @@ static void make_alloptions(void) CHECK_ALLOC(all_options, "calloc"); memcpy(all_options, const_options, sizeof(const_options)); append_protocols(all_options, ARRAY_SIZE(const_options) - 1, builtins, get_num_builtins()); +#endif } /* Performs a first scan of command line options to see if a configuration file @@ -497,7 +553,7 @@ static void make_alloptions(void) * * prots: newly-allocated list of configured protocols, if any. */ -static void cmdline_config(int argc, char* argv[], struct proto** prots) +static void cmdline_config(int argc, char* argv[], struct config_protocols_item** prots) { #ifdef LIBCONFIG int c, res; @@ -513,7 +569,7 @@ static void cmdline_config(int argc, char* argv[], struct proto** prots) opterr = 0; /* we're missing protocol options at this stage so don't output errors */ while ((c = getopt_long_only(argc, argv, optstr, all_options, NULL)) != -1) { if (c == 'v') { - verbose++; + cfg.verbose++; } if (c == 'F') { config_filename = optarg; @@ -522,10 +578,10 @@ static void cmdline_config(int argc, char* argv[], struct proto** prots) } else { /* No configuration file specified -- try default file locations */ res = config_parse("/etc/sslh/sslh.cfg", &addr_listen, prots); - if (!res && verbose) fprintf(stderr, "Using /etc/sslh/sslh.cfg\n"); + if (!res && cfg.verbose) fprintf(stderr, "Using /etc/sslh/sslh.cfg\n"); if (res) { res = config_parse("/etc/sslh.cfg", &addr_listen, prots); - if (!res && verbose) fprintf(stderr, "Using /etc/sslh.cfg\n"); + if (!res && cfg.verbose) fprintf(stderr, "Using /etc/sslh.cfg\n"); } } if (res) @@ -539,11 +595,13 @@ static void cmdline_config(int argc, char* argv[], struct proto** prots) /* Parse command-line options. prots points to a list of configured protocols, * potentially non-allocated */ -static void parse_cmdline(int argc, char* argv[], struct proto* prots) +static void parse_cmdline(int argc, char* argv[], struct config_protocols_item* prots) { +#if 0 int c; struct addrinfo **a; - struct proto *p; + struct config_protocols_item *p; + int background; optind = 1; opterr = 1; @@ -556,7 +614,7 @@ next_arg: for (p = prots; p && p->next; p = p->next) { /* override if protocol was already defined by config file * (note it only overrides address and use builtin probe) */ - if (!strcmp(p->description, builtins[c-PROT_SHIFT].description)) { + if (!strcmp(p->name, builtins[c-PROT_SHIFT].name)) { resolve_name(&(p->saddr), optarg); p->probe = builtins[c-PROT_SHIFT].probe; goto next_arg; @@ -583,10 +641,8 @@ next_arg: case 'F': /* Legal option, but do nothing, it was already processed in * cmdline_config() */ -#ifndef LIBCONFIG fprintf(stderr, "Built without libconfig support: configuration file not available.\n"); exit(1); -#endif break; case 't': @@ -631,16 +687,20 @@ next_arg: } } + return; + if (!prots) { fprintf(stderr, "At least one target protocol must be specified.\n"); exit(2); } + /* set_protocol_list(prots); + */ /* If compiling with systemd socket support no need to require listen address */ #ifndef SYSTEMD - if (!addr_listen && !inetd) { + if (!addr_listen && !cfg.inetd) { fprintf(stderr, "No listening address specified; use at least one -p option\n"); exit(1); } @@ -648,8 +708,9 @@ next_arg: /* Did command-line override foreground setting? */ if (background) - foreground = 0; + cfg.foreground = 0; +#endif } int main(int argc, char *argv[]) @@ -658,26 +719,26 @@ int main(int argc, char *argv[]) extern char *optarg; extern int optind; int res, num_addr_listen; - struct proto* protocols = NULL; + struct config_protocols_item* protocols = NULL; int *listen_sockets; /* Init defaults */ - pid_file = NULL; - user_name = NULL; - chroot_path = NULL; + cfg.pidfile = NULL; + cfg.user = NULL; + cfg.chroot = NULL; cmdline_config(argc, argv, &protocols); parse_cmdline(argc, argv, protocols); - if (inetd) + if (cfg.inetd) { - verbose = 0; + cfg.verbose = 0; start_shoveler(0); exit(0); } - if (verbose) + if (cfg.verbose) printsettings(); num_addr_listen = start_listen_sockets(&listen_sockets, addr_listen); @@ -689,7 +750,7 @@ int main(int argc, char *argv[]) } #endif - if (!foreground) { + if (!cfg.foreground) { if (fork() > 0) exit(0); /* Detach */ /* New session -- become group leader */ @@ -701,16 +762,16 @@ int main(int argc, char *argv[]) setup_signals(); - if (pid_file) - write_pid_file(pid_file); + if (cfg.pidfile) + write_pid_file(cfg.pidfile); /* Open syslog connection before we drop privs/chroot */ setup_syslog(argv[0]); - if (user_name || chroot_path) - drop_privileges(user_name, chroot_path); + if (cfg.user || cfg.chroot) + drop_privileges(cfg.user, cfg.chroot); - if (verbose) + if (cfg.verbose) printcaps(); main_loop(listen_sockets, num_addr_listen); diff --git a/sslh-select.c b/sslh-select.c index ebc2cc8..a2ced55 100644 --- a/sslh-select.c +++ b/sslh-select.c @@ -60,7 +60,7 @@ int tidy_connection(struct connection *cnx, fd_set *fds, fd_set *fds2) for (i = 0; i < 2; i++) { if (cnx->q[i].fd != -1) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "closing fd %d\n", cnx->q[i].fd); FD_CLR(cnx->q[i].fd, fds); @@ -111,7 +111,7 @@ int accept_new_connection(int listen_socket, struct connection *cnx[], int* cnx_ /* nothing */ } if (free >= *cnx_size) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "buying more slots from the slot machine.\n"); new = realloc(*cnx, (*cnx_size + cnx_num_alloc) * sizeof((*cnx)[0])); if (!new) { @@ -127,9 +127,9 @@ int accept_new_connection(int listen_socket, struct connection *cnx[], int* cnx_ } (*cnx)[free].q[0].fd = in_socket; (*cnx)[free].state = ST_PROBING; - (*cnx)[free].probe_timeout = time(NULL) + probing_timeout; + (*cnx)[free].probe_timeout = time(NULL) + cfg.timeout; - if (verbose) + if (cfg.verbose) fprintf(stderr, "accepted fd %d on slot %d\n", in_socket, free); return in_socket; @@ -169,7 +169,7 @@ void shovel(struct connection *cnx, int active_fd, read_q = &cnx->q[active_fd]; write_q = &cnx->q[1-active_fd]; - if (verbose) + if (cfg.verbose) fprintf(stderr, "activity on fd%d\n", read_q->fd); switch(fd2fd(write_q, read_q)) { @@ -223,7 +223,7 @@ void shovel_single(struct connection *cnx) if (FD_ISSET(cnx->q[i].fd, &fds_w)) { res = flush_deferred(&cnx->q[i]); if ((res == -1) && ((errno == EPIPE) || (errno == ECONNRESET))) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "%s socket closed\n", i ? "server" : "client"); return; } @@ -231,7 +231,7 @@ void shovel_single(struct connection *cnx) if (FD_ISSET(cnx->q[i].fd, &fds_r)) { res = fd2fd(&cnx->q[1-i], &cnx->q[i]); if (!res) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "socket closed\n"); return; } @@ -269,7 +269,7 @@ void connect_proxy(struct connection *cnx) close(in_socket); close(out_socket); - if (verbose) + if (cfg.verbose) fprintf(stderr, "connection closed down\n"); exit(0); @@ -329,12 +329,12 @@ void main_loop(int listen_sockets[], int num_addr_listen) while (1) { memset(&tv, 0, sizeof(tv)); - tv.tv_sec = probing_timeout; + tv.tv_sec = cfg.timeout; memcpy(&readfds, &fds_r, sizeof(readfds)); memcpy(&writefds, &fds_w, sizeof(writefds)); - if (verbose) + if (cfg.verbose) fprintf(stderr, "selecting... max_fd=%d num_probing=%d\n", max_fd, num_probing); res = select(max_fd, &readfds, &writefds, NULL, num_probing ? &tv : NULL); if (res < 0) @@ -363,7 +363,7 @@ void main_loop(int listen_sockets[], int num_addr_listen) if ((res == -1) && ((errno == EPIPE) || (errno == ECONNRESET))) { if (cnx[i].state == ST_PROBING) num_probing--; tidy_connection(&cnx[i], &fds_r, &fds_w); - if (verbose) + if (cfg.verbose) fprintf(stderr, "closed slot %d\n", i); } else { /* If no deferred data is left, stop monitoring the fd @@ -383,7 +383,7 @@ void main_loop(int listen_sockets[], int num_addr_listen) for (j = 0; j < 2; j++) { if (is_fd_active(cnx[i].q[j].fd, &readfds) || ((cnx[i].state == ST_PROBING) && (cnx[i].probe_timeout < time(NULL)))) { - if (verbose) + if (cfg.verbose) fprintf(stderr, "processing fd%d slot %d\n", j, i); switch (cnx[i].state) { @@ -399,10 +399,10 @@ void main_loop(int listen_sockets[], int num_addr_listen) * data so probe the protocol */ if ((cnx[i].probe_timeout < time(NULL))) { cnx[i].proto = timeout_protocol(); - if (verbose) + if (cfg.verbose) log_message(LOG_INFO, "timed out, connect to %s\n", - cnx[i].proto->description); + cnx[i].proto->name); } else { res = probe_client_protocol(&cnx[i]); if (res == PROBE_AGAIN) diff --git a/sslhconf.cfg b/sslhconf.cfg index 9ed160a..68db55c 100644 --- a/sslhconf.cfg +++ b/sslhconf.cfg @@ -1,52 +1,71 @@ header: "sslh-conf.h"; parser: "sslh-conf.c"; -config: ( - { name: "verbose"; type: "boolean"; default: false }, - { name: "foreground"; type: "boolean"; default: false; }, - { name: "inetd"; type: "boolean"; default: false; }, - { name: "numeric"; type: "boolean"; default: false; }, - { name: "transparent"; type: "boolean"; default: false; }, - { name: "timeout"; type: "int"; default: 2; }, - { name: "user"; type: "string"; optional: true; }, - { name: "pidfile"; type: "string"; optional: true; }, - { name: "chroot"; type: "string"; }, - { name: "syslog_facility"; type: "string"; default: "auth"; }, +# List of includes to define runtime types +# (bug in libconfig? if swallows the brackets if they start +# the string) +includes: ( + "probe.h", + " ", + " ", + " " + ); - {name: "on_timeout"; type: "string"; default: "ssh"; }, +config: { + name : "config", + type: "list", + items: ( + { name: "verbose"; type: "int"; default: 0; }, + { name: "foreground"; type: "boolean"; default: false; }, + { name: "inetd"; type: "boolean"; default: false; }, + { name: "numeric"; type: "boolean"; default: false; }, + { name: "transparent"; type: "boolean"; default: false; }, + { name: "timeout"; type: "int"; default: 2; }, + { name: "user"; type: "string"; optional: true; }, + { name: "pidfile"; type: "string"; optional: true; }, + { name: "chroot"; type: "string"; optional: true; }, + { name: "syslog_facility"; type: "string"; default: "auth"; }, - { name: "listen", - type: "list", - items: ( - { name: "host"; type: "string"; }, - { name: "port"; type: "string"; }, - { name: "keepalive"; type: "boolean"; default: false; } - ) - }, + {name: "on_timeout"; type: "string"; default: "ssh"; }, - { name: "protocols", - type: "list", - items: ( - { name: "name"; type: "string"; }, - { name: "host"; type: "string"; }, - { name: "port"; type: "string"; }, - { name: "service"; type: "string"; optional: true; }, - { name: "fork"; type: "boolean"; default: false }, - { name: "log_level"; type: "int"; default: 1 }, - { name: "keepalive"; type: "boolean"; default: false }, - { name: "sni_hostnames", - type: "array", - element_type: "string" + { name: "listen", + type: "list", + items: ( + { name: "host"; type: "string"; var: true; }, + { name: "port"; type: "string"; var: true; }, + { name: "keepalive"; type: "boolean"; default: false; } + ) }, - { name: "alpn_protocols", - type: "array", - element_type: "string" - }, - { name: "regex_patterns", - type: "array", - element_type: "string" - } - ) - } -) + + { name: "protocols", + type: "list", + items: ( + { name: "name"; type: "string"; }, + { name: "host"; type: "string"; var: true; }, + { name: "port"; type: "string"; var: true; }, + { name: "service"; type: "string"; optional: true; }, + { name: "fork"; type: "boolean"; default: false }, + { name: "log_level"; type: "int"; default: 1 }, + { name: "keepalive"; type: "boolean"; default: false }, + { name: "sni_hostnames", + type: "array", + element_type: "string" + }, + { name: "alpn_protocols", + type: "array", + element_type: "string" + }, + { name: "regex_patterns", + type: "array", + element_type: "string" + }, + + # Runtime data + { name: "probe"; type: "runtime"; c_type: "T_PROBE*" }, + { name: "saddr"; type: "runtime"; c_type: "struct addrinfo*" }, + { name: "data"; type: "runtime"; c_type: "void*" } + ) + } + ) +} diff --git a/test.cfg b/test.cfg index 7a7824b..f468683 100644 --- a/test.cfg +++ b/test.cfg @@ -31,12 +31,12 @@ protocols: { name: "xmpp"; host: "localhost"; port: "9009"; }, { name: "adb"; host: "localhost"; port: "9010"; }, { name: "tls"; host: "localhost"; port: "9021"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni1" ]; }, - { name: "ssl"; host: "localhost"; port: "9022"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni2", "sni3" ]; }, + { name: "tls"; host: "localhost"; port: "9022"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni2", "sni3" ]; }, { name: "tls"; host: "localhost"; port: "9023"; alpn_protocols: [ "alpn3" ]; }, { name: "tls"; host: "localhost"; port: "9024"; sni_hostnames: [ "sni3" ]; }, - { name: "ssl"; host: "localhost"; port: "9025"; }, + { name: "tls"; host: "localhost"; port: "9025"; }, { name: "anyprot"; host: "localhost"; port: "9099"; } ); -on-timeout: "ssh"; +on_timeout: "ssh"; diff --git a/tls.c b/tls.c index 2f3e55f..c8b3fae 100644 --- a/tls.c +++ b/tls.c @@ -32,6 +32,7 @@ #include /* malloc() */ #include /* fnmatch() */ #include "tls.h" +#include "sslh-conf.h" #define TLS_HEADER_LEN 5 #define TLS_HANDSHAKE_CONTENT_TYPE 0x16 @@ -48,14 +49,16 @@ typedef struct { struct TLSProtocol { TLS_MATCHMODE match_mode; - char** sni_hostname_list; - char** alpn_protocol_list; + int sni_list_len; + const char** sni_hostname_list; + int alpn_list_len; + const char** alpn_protocol_list; }; static int parse_extensions(const struct TLSProtocol *, const char *, size_t); static int parse_server_name_extension(const struct TLSProtocol *, const char *, size_t); static int parse_alpn_extension(const struct TLSProtocol *, const char *, size_t); -static int has_match(char**, const char*, size_t); +static int has_match(const char**, size_t, const char*, size_t); /* Parse a TLS packet for the Server Name Indication and ALPN extension in the client * hello handshake, returning a status code @@ -79,14 +82,14 @@ parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t da tls_content_type = data[0]; if (tls_content_type != TLS_HANDSHAKE_CONTENT_TYPE) { - if (verbose) fprintf(stderr, "Request did not begin with TLS handshake.\n"); + if (cfg.verbose) fprintf(stderr, "Request did not begin with TLS handshake.\n"); return TLS_EPROTOCOL; } tls_version_major = data[1]; tls_version_minor = data[2]; if (tls_version_major < 3) { - if (verbose) fprintf(stderr, "Received SSL %d.%d handshake which cannot be parsed.\n", + if (cfg.verbose) fprintf(stderr, "Received SSL %d.%d handshake which cannot be parsed.\n", tls_version_major, tls_version_minor); return TLS_EVERSION; @@ -108,7 +111,7 @@ parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t da return TLS_EPROTOCOL; } if (data[pos] != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) { - if (verbose) fprintf(stderr, "Not a client hello\n"); + if (cfg.verbose) fprintf(stderr, "Not a client hello\n"); return TLS_EPROTOCOL; } @@ -141,7 +144,7 @@ parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t da pos += 1 + len; if (pos == data_len && tls_version_major == 3 && tls_version_minor == 0) { - if (verbose) fprintf(stderr, "Received SSL 3.0 handshake without extensions\n"); + if (cfg.verbose) fprintf(stderr, "Received SSL 3.0 handshake without extensions\n"); return TLS_EVERSION; } @@ -219,13 +222,13 @@ parse_server_name_extension(const struct TLSProtocol *tls_data, const char *data switch (data[pos]) { /* name type */ case 0x00: /* host_name */ - if(has_match(tls_data->sni_hostname_list, data + pos + 3, len)) { + if(has_match(tls_data->sni_hostname_list, tls_data->sni_list_len, data + pos + 3, len)) { return len; } else { return TLS_ENOEXT; } default: - if (verbose) fprintf(stderr, "Unknown server name extension name type: %d\n", + if (cfg.verbose) fprintf(stderr, "Unknown server name extension name type: %d\n", data[pos]); } pos += 3 + len; @@ -248,10 +251,10 @@ parse_alpn_extension(const struct TLSProtocol *tls_data, const char *data, size_ if (pos + 1 + len > data_len) return TLS_EPROTOCOL; - if (len > 0 && has_match(tls_data->alpn_protocol_list, data + pos + 1, len)) { + if (len > 0 && has_match(tls_data->alpn_protocol_list, tls_data->alpn_list_len, data + pos + 1, len)) { return len; } else if (len > 0) { - if (verbose) fprintf(stderr, "Unknown ALPN name: %.*s\n", (int)len, data + pos + 1); + if (cfg.verbose) fprintf(stderr, "Unknown ALPN name: %.*s\n", (int)len, data + pos + 1); } pos += 1 + len; } @@ -263,15 +266,17 @@ parse_alpn_extension(const struct TLSProtocol *tls_data, const char *data, size_ } static int -has_match(char** list, const char* name, size_t name_len) { - char **item; +has_match(const char** list, size_t list_len, const char* name, size_t name_len) { + const char **item; + int i; char *name_nullterminated = malloc(name_len+1); CHECK_ALLOC(name_nullterminated, "malloc"); memcpy(name_nullterminated, name, name_len); name_nullterminated[name_len]='\0'; - for (item = list; *item; item++) { - if (verbose) fprintf(stderr, "matching [%.*s] with [%s]\n", (int)name_len, name, *item); + for (i = 0; i < list_len; i++) { + item = &list[i]; + if (cfg.verbose) fprintf(stderr, "matching [%.*s] with [%s]\n", (int)name_len, name, *item); if(!fnmatch(*item, name_nullterminated, 0)) { free(name_nullterminated); return 1; @@ -292,12 +297,14 @@ new_tls_data() { } struct TLSProtocol * -tls_data_set_list(struct TLSProtocol *tls_data, int alpn, char** list) { +tls_data_set_list(struct TLSProtocol *tls_data, int alpn, const char** list, size_t list_len) { if (alpn) { tls_data->alpn_protocol_list = list; + tls_data->alpn_list_len = list_len; tls_data->match_mode.tls_match_alpn = 1; } else { tls_data->sni_hostname_list = list; + tls_data->sni_list_len = list_len; tls_data->match_mode.tls_match_sni = 1; } diff --git a/tls.h b/tls.h index 6ef0ebf..c6cf1a7 100644 --- a/tls.h +++ b/tls.h @@ -33,7 +33,7 @@ struct TLSProtocol; int parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t data_len); struct TLSProtocol *new_tls_data(); -struct TLSProtocol *tls_data_set_list(struct TLSProtocol *, int, char**); +struct TLSProtocol *tls_data_set_list(struct TLSProtocol *, int, const char**, size_t); #define TLS_MATCH 1 #define TLS_NOMATCH 0 From d3d4fd657a4d65eceeb12bd536b966b331c9d742 Mon Sep 17 00:00:00 2001 From: yrutschle Date: Mon, 3 Dec 2018 11:02:20 +0100 Subject: [PATCH 2/5] moved config parse to c2s code --- sslh-conf.c | 24 ++++++++++++++++++++++-- sslh-conf.h | 16 ++++++++-------- sslh-main.c | 25 +++---------------------- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/sslh-conf.c b/sslh-conf.c index df022e5..44ae20d 100644 --- a/sslh-conf.c +++ b/sslh-conf.c @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct) - * on Wed Nov 28 23:38:56 2018. */ + * on Mon Dec 3 10:48:52 2018. */ @@ -169,7 +169,7 @@ static int config_listen_parser( return 1; } -int config_parser( +static int config_parser( config_setting_t* cfg, struct config_item* config, const char** errmsg) @@ -293,6 +293,26 @@ int config_parser( return 1; } +/* Public parser API: returns 0 on failure, 1 on success */ +int config_parse_file(const char* filename, struct config_item* cfg, const char**errmsg) +{ + config_t c; + + config_init(&c); + if (config_read_file(&c, filename) == CONFIG_FALSE) { + if (config_error_line(&c) != 0) { + asprintf(errmsg, "%s:%d:%s", + filename, + config_error_line(&c), + config_error_text(&c)); + return 0; + } + asprintf(errmsg, "%s:%s", filename, config_error_text(&c)); + return 0; + } + return config_parser(config_lookup(&c, "/"), cfg, errmsg); +} + static void indent(int depth) { int i; diff --git a/sslh-conf.h b/sslh-conf.h index 8cf787a..28efd4b 100644 --- a/sslh-conf.h +++ b/sslh-conf.h @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct) - * on Wed Nov 28 23:38:56 2018. */ + * on Mon Dec 3 10:48:52 2018. */ #ifndef C2S_CONFIG_H @@ -26,11 +26,11 @@ struct config_protocols_item { int fork; int log_level; int keepalive; - int sni_hostnames_len; + size_t sni_hostnames_len; const char** sni_hostnames; - int alpn_protocols_len; + size_t alpn_protocols_len; const char** alpn_protocols; - int regex_patterns_len; + size_t regex_patterns_len; const char** regex_patterns; T_PROBE* probe; struct addrinfo* saddr; @@ -52,14 +52,14 @@ struct config_item { const char* chroot; const char* syslog_facility; const char* on_timeout; - int listen_len; + size_t listen_len; struct config_listen_item* listen; - int protocols_len; + size_t protocols_len; struct config_protocols_item* protocols; }; -int config_parser( - config_setting_t* cfg, +int config_parse_file( + const char* filename, struct config_item* config, const char** errmsg); diff --git a/sslh-main.c b/sslh-main.c index 9a8543e..80a2927 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -475,32 +475,13 @@ static int config_protocols(config_t *config, struct proto **prots) #ifdef LIBCONFIG static int config_parse(char *filename, struct addrinfo **listen, struct config_protocols_item **prots) { - config_t config; int res; - const char*err; + const char* err; - config_init(&config); - if (config_read_file(&config, filename) == CONFIG_FALSE) { - /* If it's a parse error then there will be a line number for the failure - * an I/O error (such as non-existent file) will have the error line as 0 - */ - if (config_error_line(&config) != 0) { - fprintf(stderr, "%s:%d:%s\n", - filename, - config_error_line(&config), - config_error_text(&config)); - exit(1); - } - fprintf(stderr, "%s:%s\n", - filename, - config_error_text(&config)); + if (!config_parse_file(filename, &cfg, &err)) { + fprintf(stderr, err); return 1; } - res = config_parser(config_lookup(&config, "/"), &cfg, &err); - if (!res) { - fprintf(stderr, "%s\n", err); - exit(1); - } config_resolve_listen(listen); config_protocols(); From 33ab9d535dc3a9b6246d774d64d09e7a8802a792 Mon Sep 17 00:00:00 2001 From: yrutschle Date: Tue, 4 Dec 2018 23:11:04 +0100 Subject: [PATCH 3/5] code cleanup and adaptation of regex probe --- common.c | 2 +- common.h | 4 +- probe.c | 48 ++++----- probe.h | 12 +-- sslh-conf.c | 263 +++++++++++++++++++++++++------------------------- sslh-conf.h | 24 ++--- sslh-main.c | 268 +++++++-------------------------------------------- sslhconf.cfg | 4 +- t | 28 ++++-- test.cfg | 3 + 10 files changed, 233 insertions(+), 423 deletions(-) diff --git a/common.c b/common.c index c0bdc54..0c5244e 100644 --- a/common.c +++ b/common.c @@ -33,7 +33,7 @@ /* * Settings that depend on the command line or the config file */ -struct config_item cfg; +struct sslhcfg_item cfg; struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */ diff --git a/common.h b/common.h index a6478e5..97beb47 100644 --- a/common.h +++ b/common.h @@ -87,7 +87,7 @@ struct queue { struct connection { enum connection_state state; time_t probe_timeout; - struct config_protocols_item* proto; + struct sslhcfg_protocols_item* proto; /* q[0]: queue for external connection (client); * q[1]: queue for internal connection (httpd or sshd); @@ -123,7 +123,7 @@ int flush_deferred(struct queue *q); extern int probing_timeout, verbose, inetd, foreground, background, transparent, numeric; -extern struct config_item cfg; +extern struct sslhcfg_item cfg; extern struct sockaddr_storage addr_ssl, addr_ssh, addr_openvpn; extern struct addrinfo *addr_listen; extern const char* USAGE_STRING; diff --git a/probe.c b/probe.c index 6c280c0..ca4c152 100644 --- a/probe.c +++ b/probe.c @@ -33,15 +33,15 @@ -static int is_ssh_protocol(const char *p, int len, struct config_protocols_item*); -static int is_openvpn_protocol(const char *p, int len, struct config_protocols_item*); -static int is_tinc_protocol(const char *p, int len, struct config_protocols_item*); -static int is_xmpp_protocol(const char *p, int len, struct config_protocols_item*); -static int is_http_protocol(const char *p, int len, struct config_protocols_item*); -static int is_tls_protocol(const char *p, int len, struct config_protocols_item*); -static int is_adb_protocol(const char *p, int len, struct config_protocols_item*); -static int is_socks5_protocol(const char *p, int len, struct config_protocols_item*); -static int is_true(const char *p, int len, struct config_protocols_item* proto) { return 1; } +static int is_ssh_protocol(const char *p, int len, struct sslhcfg_protocols_item*); +static int is_openvpn_protocol(const char *p, int len, struct sslhcfg_protocols_item*); +static int is_tinc_protocol(const char *p, int len, struct sslhcfg_protocols_item*); +static int is_xmpp_protocol(const char *p, int len, struct sslhcfg_protocols_item*); +static int is_http_protocol(const char *p, int len, struct sslhcfg_protocols_item*); +static int is_tls_protocol(const char *p, int len, struct sslhcfg_protocols_item*); +static int is_adb_protocol(const char *p, int len, struct sslhcfg_protocols_item*); +static int is_socks5_protocol(const char *p, int len, struct sslhcfg_protocols_item*); +static int is_true(const char *p, int len, struct sslhcfg_protocols_item* proto) { return 1; } struct protocol_probe_desc { const char* name; @@ -64,11 +64,11 @@ static struct protocol_probe_desc builtins[] = { { "anyprot", is_true } }; -static struct config_protocols_item *protocols; +static struct sslhcfg_protocols_item *protocols; static char* on_timeout = "ssh"; /* TODO I think this has to go */ -struct config_protocols_item* get_builtins(void) { +struct sslhcfg_protocols_item* get_builtins(void) { return NULL; } @@ -86,7 +86,7 @@ void set_ontimeout(const char* name) /* Returns the protocol to connect to in case of timeout; * if not found, return the first protocol specified */ -struct config_protocols_item* timeout_protocol(void) +struct sslhcfg_protocols_item* timeout_protocol(void) { int i; for (i = 0; i < cfg.protocols_len; i++) { @@ -97,12 +97,12 @@ struct config_protocols_item* timeout_protocol(void) } /* returns the first protocol (caller can then follow the *next pointers) */ -struct config_protocols_item* get_first_protocol(void) +struct sslhcfg_protocols_item* get_first_protocol(void) { return protocols; } -void set_protocol_list(struct config_protocols_item* prots) +void set_protocol_list(struct sslhcfg_protocols_item* prots) { #if 0 protocols = prots; @@ -143,7 +143,7 @@ void hexdump(const char *mem, unsigned int len) } /* Is the buffer the beginning of an SSH connection? */ -static int is_ssh_protocol(const char *p, int len, struct config_protocols_item* proto) +static int is_ssh_protocol(const char *p, int len, struct sslhcfg_protocols_item* proto) { if (len < 4) return PROBE_AGAIN; @@ -161,7 +161,7 @@ static int is_ssh_protocol(const char *p, int len, struct config_protocols_item* * http://www.fengnet.com/book/vpns%20illustrated%20tunnels%20%20vpnsand%20ipsec/ch08lev1sec5.html * and OpenVPN ssl.c, ssl.h and options.c */ -static int is_openvpn_protocol (const char*p,int len, struct config_protocols_item* proto) +static int is_openvpn_protocol (const char*p,int len, struct sslhcfg_protocols_item* proto) { int packet_len; @@ -176,7 +176,7 @@ static int is_openvpn_protocol (const char*p,int len, struct config_protocols_it * Protocol is documented here: http://www.tinc-vpn.org/documentation/tinc.pdf * First connection starts with "0 " in 1.0.15) * */ -static int is_tinc_protocol( const char *p, int len, struct config_protocols_item* proto) +static int is_tinc_protocol( const char *p, int len, struct sslhcfg_protocols_item* proto) { if (len < 2) return PROBE_AGAIN; @@ -188,7 +188,7 @@ static int is_tinc_protocol( const char *p, int len, struct config_protocols_ite * (Protocol is documented (http://tools.ietf.org/html/rfc6120) but for lazy * clients, just checking first frame containing "jabber" in xml entity) * */ -static int is_xmpp_protocol( const char *p, int len, struct config_protocols_item* proto) +static int is_xmpp_protocol( const char *p, int len, struct sslhcfg_protocols_item* proto) { if (memmem(p, len, "jabber", 6)) return PROBE_MATCH; @@ -211,7 +211,7 @@ static int probe_http_method(const char *p, int len, const char *opt) } /* Is the buffer the beginning of an HTTP connection? */ -static int is_http_protocol(const char *p, int len, struct config_protocols_item* proto) +static int is_http_protocol(const char *p, int len, struct sslhcfg_protocols_item* proto) { int res; /* If it's got HTTP in the request (HTTP/1.1) then it's HTTP */ @@ -237,7 +237,7 @@ static int is_http_protocol(const char *p, int len, struct config_protocols_item } /* Says if it's TLS, optionally with SNI and ALPN lists in proto->data */ -static int is_tls_protocol(const char *p, int len, struct config_protocols_item* proto) +static int is_tls_protocol(const char *p, int len, struct sslhcfg_protocols_item* proto) { switch (parse_tls_header(proto->data, p, len)) { case TLS_MATCH: return PROBE_MATCH; @@ -257,7 +257,7 @@ static int probe_adb_cnxn_message(const char *p) return !memcmp(&p[0], "CNXN", 4) && !memcmp(&p[24], "host:", 5); } -static int is_adb_protocol(const char *p, int len, struct config_protocols_item* proto) +static int is_adb_protocol(const char *p, int len, struct sslhcfg_protocols_item* proto) { /* amessage.data_length is not being checked, under the assumption that * a packet >= 30 bytes will have "something" in the payload field. @@ -296,7 +296,7 @@ static int is_adb_protocol(const char *p, int len, struct config_protocols_item* return probe_adb_cnxn_message(&p[sizeof(empty_message)]); } -static int is_socks5_protocol(const char *p_in, int len, struct config_protocols_item* proto) +static int is_socks5_protocol(const char *p_in, int len, struct sslhcfg_protocols_item* proto) { unsigned char* p = (unsigned char*)p_in; int i; @@ -329,7 +329,7 @@ static int is_socks5_protocol(const char *p_in, int len, struct config_protocols return PROBE_MATCH; } -static int regex_probe(const char *p, int len, struct config_protocols_item* proto) +static int regex_probe(const char *p, int len, struct sslhcfg_protocols_item* proto) { #ifdef ENABLE_REGEX regex_t **probe = proto->data; @@ -355,7 +355,7 @@ static int regex_probe(const char *p, int len, struct config_protocols_item* pro int probe_client_protocol(struct connection *cnx) { char buffer[BUFSIZ]; - struct config_protocols_item* p, *last_p = cnx->proto; + struct sslhcfg_protocols_item* p, *last_p = cnx->proto; int i, n, res, again = 0; n = read(cnx->q[0].fd, buffer, sizeof(buffer)); diff --git a/probe.h b/probe.h index 0e465f9..7119789 100644 --- a/probe.h +++ b/probe.h @@ -12,8 +12,8 @@ typedef enum { PROBE_AGAIN, /* Not enough data for this probe, try again with more data */ } probe_result; -struct config_protocols_item; -typedef int T_PROBE(const char*, int, struct config_protocols_item*); +struct sslhcfg_protocols_item; +typedef int T_PROBE(const char*, int, struct sslhcfg_protocols_item*); #include "sslh-conf.h" @@ -39,7 +39,7 @@ struct proto { #endif /* Returns a pointer to the array of builtin protocols */ -struct config_protocols_item* get_builtins(void); +struct sslhcfg_protocols_item* get_builtins(void); /* Returns the number of builtin protocols */ int get_num_builtins(void); @@ -48,10 +48,10 @@ int get_num_builtins(void); T_PROBE* get_probe(const char* description); /* Returns the head of the configured protocols */ -struct config_protocols_item* get_first_protocol(void); +struct sslhcfg_protocols_item* get_first_protocol(void); /* Set the list of configured protocols */ -void set_protocol_list(struct config_protocols_item*); +void set_protocol_list(struct sslhcfg_protocols_item*); /* probe_client_protocol * @@ -69,7 +69,7 @@ void set_ontimeout(const char* name); * * Returns the protocol to connect to in case of timeout */ -struct config_protocols_item* timeout_protocol(void); +struct sslhcfg_protocols_item* timeout_protocol(void); void hexdump(const char*, unsigned int); diff --git a/sslh-conf.c b/sslh-conf.c index 44ae20d..e4fecdf 100644 --- a/sslh-conf.c +++ b/sslh-conf.c @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct) - * on Mon Dec 3 10:48:52 2018. */ + * on Tue Dec 4 21:49:45 2018. */ @@ -9,9 +9,9 @@ #include #include "sslh-conf.h" -static int config_protocols_parser( +static int sslhcfg_protocols_parser( config_setting_t* cfg, - struct config_protocols_item* config_protocols, + struct sslhcfg_protocols_item* sslhcfg_protocols, const char** errmsg) { config_setting_t* setting; @@ -19,112 +19,112 @@ static int config_protocols_parser( *errmsg = NULL; if (config_setting_lookup(cfg, "name")) { - if (config_setting_lookup_string(cfg, "name", &config_protocols->name) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "name", &sslhcfg_protocols->name) == CONFIG_FALSE) { *errmsg = "Parsing of option \"name\" failed"; return 0; } } else { - *errmsg = "Mandatory option \"name\" is missing"; + *errmsg = "Mandatory option \"sslhcfg_protocols.name\" is missing"; return 0; } if (config_setting_lookup(cfg, "host")) { - if (config_setting_lookup_string(cfg, "host", &config_protocols->host) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "host", &sslhcfg_protocols->host) == CONFIG_FALSE) { *errmsg = "Parsing of option \"host\" failed"; return 0; } } else { - *errmsg = "Mandatory option \"host\" is missing"; + *errmsg = "Mandatory option \"sslhcfg_protocols.host\" is missing"; return 0; } - if (asprintf(&tmp, "%s", config_protocols->host) == -1) { + if (asprintf(&tmp, "%s", sslhcfg_protocols->host) == -1) { *errmsg = "asprintf: cannot allocate memory"; return 0; } - config_protocols->host = tmp; + sslhcfg_protocols->host = tmp; if (config_setting_lookup(cfg, "port")) { - if (config_setting_lookup_string(cfg, "port", &config_protocols->port) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "port", &sslhcfg_protocols->port) == CONFIG_FALSE) { *errmsg = "Parsing of option \"port\" failed"; return 0; } } else { - *errmsg = "Mandatory option \"port\" is missing"; + *errmsg = "Mandatory option \"sslhcfg_protocols.port\" is missing"; return 0; } - if (asprintf(&tmp, "%s", config_protocols->port) == -1) { + if (asprintf(&tmp, "%s", sslhcfg_protocols->port) == -1) { *errmsg = "asprintf: cannot allocate memory"; return 0; } - config_protocols->port = tmp; - config_protocols->service = NULL; + sslhcfg_protocols->port = tmp; + sslhcfg_protocols->service = NULL; if (config_setting_lookup(cfg, "service")) { - if (config_setting_lookup_string(cfg, "service", &config_protocols->service) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "service", &sslhcfg_protocols->service) == CONFIG_FALSE) { *errmsg = "Parsing of option \"service\" failed"; return 0; } else { - config_protocols->service_is_present = 1; + sslhcfg_protocols->service_is_present = 1; } ; } - config_protocols->fork = 0; + sslhcfg_protocols->fork = 0; if (config_setting_lookup(cfg, "fork")) { - if (config_setting_lookup_bool(cfg, "fork", &config_protocols->fork) == CONFIG_FALSE) { + if (config_setting_lookup_bool(cfg, "fork", &sslhcfg_protocols->fork) == CONFIG_FALSE) { *errmsg = "Parsing of option \"fork\" failed"; return 0; } ; } - config_protocols->log_level = 1; + sslhcfg_protocols->log_level = 1; if (config_setting_lookup(cfg, "log_level")) { - if (config_setting_lookup_int(cfg, "log_level", &config_protocols->log_level) == CONFIG_FALSE) { + if (config_setting_lookup_int(cfg, "log_level", &sslhcfg_protocols->log_level) == CONFIG_FALSE) { *errmsg = "Parsing of option \"log_level\" failed"; return 0; } ; } - config_protocols->keepalive = 0; + sslhcfg_protocols->keepalive = 0; if (config_setting_lookup(cfg, "keepalive")) { - if (config_setting_lookup_bool(cfg, "keepalive", &config_protocols->keepalive) == CONFIG_FALSE) { + if (config_setting_lookup_bool(cfg, "keepalive", &sslhcfg_protocols->keepalive) == CONFIG_FALSE) { *errmsg = "Parsing of option \"keepalive\" failed"; return 0; } ; } - config_protocols->sni_hostnames = NULL; - config_protocols->sni_hostnames_len = 0; + sslhcfg_protocols->sni_hostnames = NULL; + sslhcfg_protocols->sni_hostnames_len = 0; if ((setting = config_setting_lookup(cfg, "sni_hostnames"))) { int len = config_setting_length(setting); - config_protocols->sni_hostnames = malloc(len * sizeof(*config_protocols->sni_hostnames)); - config_protocols->sni_hostnames_len = len; + sslhcfg_protocols->sni_hostnames = malloc(len * sizeof(*sslhcfg_protocols->sni_hostnames)); + sslhcfg_protocols->sni_hostnames_len = len; for (int i = 0; i < len; i++) { config_setting_t* s = config_setting_get_elem(setting, i); - config_protocols->sni_hostnames[i] = config_setting_get_string(s); + sslhcfg_protocols->sni_hostnames[i] = config_setting_get_string(s); } } - config_protocols->alpn_protocols = NULL; - config_protocols->alpn_protocols_len = 0; + sslhcfg_protocols->alpn_protocols = NULL; + sslhcfg_protocols->alpn_protocols_len = 0; if ((setting = config_setting_lookup(cfg, "alpn_protocols"))) { int len = config_setting_length(setting); - config_protocols->alpn_protocols = malloc(len * sizeof(*config_protocols->alpn_protocols)); - config_protocols->alpn_protocols_len = len; + sslhcfg_protocols->alpn_protocols = malloc(len * sizeof(*sslhcfg_protocols->alpn_protocols)); + sslhcfg_protocols->alpn_protocols_len = len; for (int i = 0; i < len; i++) { config_setting_t* s = config_setting_get_elem(setting, i); - config_protocols->alpn_protocols[i] = config_setting_get_string(s); + sslhcfg_protocols->alpn_protocols[i] = config_setting_get_string(s); } } - config_protocols->regex_patterns = NULL; - config_protocols->regex_patterns_len = 0; + sslhcfg_protocols->regex_patterns = NULL; + sslhcfg_protocols->regex_patterns_len = 0; if ((setting = config_setting_lookup(cfg, "regex_patterns"))) { int len = config_setting_length(setting); - config_protocols->regex_patterns = malloc(len * sizeof(*config_protocols->regex_patterns)); - config_protocols->regex_patterns_len = len; + sslhcfg_protocols->regex_patterns = malloc(len * sizeof(*sslhcfg_protocols->regex_patterns)); + sslhcfg_protocols->regex_patterns_len = len; for (int i = 0; i < len; i++) { config_setting_t* s = config_setting_get_elem(setting, i); - config_protocols->regex_patterns[i] = config_setting_get_string(s); + sslhcfg_protocols->regex_patterns[i] = config_setting_get_string(s); } } return 1; } -static int config_listen_parser( +static int sslhcfg_listen_parser( config_setting_t* cfg, - struct config_listen_item* config_listen, + struct sslhcfg_listen_item* sslhcfg_listen, const char** errmsg) { config_setting_t* setting; @@ -132,36 +132,36 @@ static int config_listen_parser( *errmsg = NULL; if (config_setting_lookup(cfg, "host")) { - if (config_setting_lookup_string(cfg, "host", &config_listen->host) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "host", &sslhcfg_listen->host) == CONFIG_FALSE) { *errmsg = "Parsing of option \"host\" failed"; return 0; } } else { - *errmsg = "Mandatory option \"host\" is missing"; + *errmsg = "Mandatory option \"sslhcfg_listen.host\" is missing"; return 0; } - if (asprintf(&tmp, "%s", config_listen->host) == -1) { + if (asprintf(&tmp, "%s", sslhcfg_listen->host) == -1) { *errmsg = "asprintf: cannot allocate memory"; return 0; } - config_listen->host = tmp; + sslhcfg_listen->host = tmp; if (config_setting_lookup(cfg, "port")) { - if (config_setting_lookup_string(cfg, "port", &config_listen->port) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "port", &sslhcfg_listen->port) == CONFIG_FALSE) { *errmsg = "Parsing of option \"port\" failed"; return 0; } } else { - *errmsg = "Mandatory option \"port\" is missing"; + *errmsg = "Mandatory option \"sslhcfg_listen.port\" is missing"; return 0; } - if (asprintf(&tmp, "%s", config_listen->port) == -1) { + if (asprintf(&tmp, "%s", sslhcfg_listen->port) == -1) { *errmsg = "asprintf: cannot allocate memory"; return 0; } - config_listen->port = tmp; - config_listen->keepalive = 0; + sslhcfg_listen->port = tmp; + sslhcfg_listen->keepalive = 0; if (config_setting_lookup(cfg, "keepalive")) { - if (config_setting_lookup_bool(cfg, "keepalive", &config_listen->keepalive) == CONFIG_FALSE) { + if (config_setting_lookup_bool(cfg, "keepalive", &sslhcfg_listen->keepalive) == CONFIG_FALSE) { *errmsg = "Parsing of option \"keepalive\" failed"; return 0; } ; @@ -169,124 +169,124 @@ static int config_listen_parser( return 1; } -static int config_parser( +static int sslhcfg_parser( config_setting_t* cfg, - struct config_item* config, + struct sslhcfg_item* sslhcfg, const char** errmsg) { config_setting_t* setting; char* tmp; *errmsg = NULL; - config->verbose = 0; + sslhcfg->verbose = 0; if (config_setting_lookup(cfg, "verbose")) { - if (config_setting_lookup_int(cfg, "verbose", &config->verbose) == CONFIG_FALSE) { + if (config_setting_lookup_int(cfg, "verbose", &sslhcfg->verbose) == CONFIG_FALSE) { *errmsg = "Parsing of option \"verbose\" failed"; return 0; } ; } - config->foreground = 0; + sslhcfg->foreground = 0; if (config_setting_lookup(cfg, "foreground")) { - if (config_setting_lookup_bool(cfg, "foreground", &config->foreground) == CONFIG_FALSE) { + if (config_setting_lookup_bool(cfg, "foreground", &sslhcfg->foreground) == CONFIG_FALSE) { *errmsg = "Parsing of option \"foreground\" failed"; return 0; } ; } - config->inetd = 0; + sslhcfg->inetd = 0; if (config_setting_lookup(cfg, "inetd")) { - if (config_setting_lookup_bool(cfg, "inetd", &config->inetd) == CONFIG_FALSE) { + if (config_setting_lookup_bool(cfg, "inetd", &sslhcfg->inetd) == CONFIG_FALSE) { *errmsg = "Parsing of option \"inetd\" failed"; return 0; } ; } - config->numeric = 0; + sslhcfg->numeric = 0; if (config_setting_lookup(cfg, "numeric")) { - if (config_setting_lookup_bool(cfg, "numeric", &config->numeric) == CONFIG_FALSE) { + if (config_setting_lookup_bool(cfg, "numeric", &sslhcfg->numeric) == CONFIG_FALSE) { *errmsg = "Parsing of option \"numeric\" failed"; return 0; } ; } - config->transparent = 0; + sslhcfg->transparent = 0; if (config_setting_lookup(cfg, "transparent")) { - if (config_setting_lookup_bool(cfg, "transparent", &config->transparent) == CONFIG_FALSE) { + if (config_setting_lookup_bool(cfg, "transparent", &sslhcfg->transparent) == CONFIG_FALSE) { *errmsg = "Parsing of option \"transparent\" failed"; return 0; } ; } - config->timeout = 2; + sslhcfg->timeout = 2; if (config_setting_lookup(cfg, "timeout")) { - if (config_setting_lookup_int(cfg, "timeout", &config->timeout) == CONFIG_FALSE) { + if (config_setting_lookup_int(cfg, "timeout", &sslhcfg->timeout) == CONFIG_FALSE) { *errmsg = "Parsing of option \"timeout\" failed"; return 0; } ; } - config->user = NULL; + sslhcfg->user = NULL; if (config_setting_lookup(cfg, "user")) { - if (config_setting_lookup_string(cfg, "user", &config->user) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "user", &sslhcfg->user) == CONFIG_FALSE) { *errmsg = "Parsing of option \"user\" failed"; return 0; } else { - config->user_is_present = 1; + sslhcfg->user_is_present = 1; } ; } - config->pidfile = NULL; + sslhcfg->pidfile = NULL; if (config_setting_lookup(cfg, "pidfile")) { - if (config_setting_lookup_string(cfg, "pidfile", &config->pidfile) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "pidfile", &sslhcfg->pidfile) == CONFIG_FALSE) { *errmsg = "Parsing of option \"pidfile\" failed"; return 0; } else { - config->pidfile_is_present = 1; + sslhcfg->pidfile_is_present = 1; } ; } - config->chroot = NULL; + sslhcfg->chroot = NULL; if (config_setting_lookup(cfg, "chroot")) { - if (config_setting_lookup_string(cfg, "chroot", &config->chroot) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "chroot", &sslhcfg->chroot) == CONFIG_FALSE) { *errmsg = "Parsing of option \"chroot\" failed"; return 0; } else { - config->chroot_is_present = 1; + sslhcfg->chroot_is_present = 1; } ; } - config->syslog_facility = "auth"; + sslhcfg->syslog_facility = "auth"; if (config_setting_lookup(cfg, "syslog_facility")) { - if (config_setting_lookup_string(cfg, "syslog_facility", &config->syslog_facility) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "syslog_facility", &sslhcfg->syslog_facility) == CONFIG_FALSE) { *errmsg = "Parsing of option \"syslog_facility\" failed"; return 0; } ; } - config->on_timeout = "ssh"; + sslhcfg->on_timeout = "ssh"; if (config_setting_lookup(cfg, "on_timeout")) { - if (config_setting_lookup_string(cfg, "on_timeout", &config->on_timeout) == CONFIG_FALSE) { + if (config_setting_lookup_string(cfg, "on_timeout", &sslhcfg->on_timeout) == CONFIG_FALSE) { *errmsg = "Parsing of option \"on_timeout\" failed"; return 0; } ; } - config->listen = NULL; - config->listen_len = 0; + sslhcfg->listen = NULL; + sslhcfg->listen_len = 0; if ((setting = config_setting_lookup(cfg, "listen"))) { int len = config_setting_length(setting); - config->listen = malloc(len * sizeof(*config->listen)); - config->listen_len = len; + sslhcfg->listen = malloc(len * sizeof(*sslhcfg->listen)); + sslhcfg->listen_len = len; for (int i = 0; i < len; i++) { config_setting_t* s = config_setting_get_elem(setting, i); - int res = config_listen_parser(s, &config->listen[i], errmsg); + int res = sslhcfg_listen_parser(s, &sslhcfg->listen[i], errmsg); if (!res) return 0; } } - config->protocols = NULL; - config->protocols_len = 0; + sslhcfg->protocols = NULL; + sslhcfg->protocols_len = 0; if ((setting = config_setting_lookup(cfg, "protocols"))) { int len = config_setting_length(setting); - config->protocols = malloc(len * sizeof(*config->protocols)); - config->protocols_len = len; + sslhcfg->protocols = malloc(len * sizeof(*sslhcfg->protocols)); + sslhcfg->protocols_len = len; for (int i = 0; i < len; i++) { config_setting_t* s = config_setting_get_elem(setting, i); - int res = config_protocols_parser(s, &config->protocols[i], errmsg); + int res = sslhcfg_protocols_parser(s, &sslhcfg->protocols[i], errmsg); if (!res) return 0; } } @@ -294,7 +294,7 @@ static int config_parser( } /* Public parser API: returns 0 on failure, 1 on success */ -int config_parse_file(const char* filename, struct config_item* cfg, const char**errmsg) +int sslhcfg_parse_file(const char* filename, struct sslhcfg_item* cfg, const char**errmsg) { config_t c; @@ -310,7 +310,7 @@ int config_parse_file(const char* filename, struct config_item* cfg, const char* asprintf(errmsg, "%s:%s", filename, config_error_text(&c)); return 0; } - return config_parser(config_lookup(&c, "/"), cfg, errmsg); + return sslhcfg_parser(config_lookup(&c, "/"), cfg, errmsg); } static void indent(int depth) @@ -320,98 +320,95 @@ static void indent(int depth) printf(" "); } -static void config_protocols_print( - struct config_protocols_item* config_protocols, +static void sslhcfg_protocols_print( + struct sslhcfg_protocols_item* sslhcfg_protocols, int depth) { int i; indent(depth); - printf("name: %s\n", config_protocols->name); + printf("name: %s\n", sslhcfg_protocols->name); indent(depth); - printf("host: %s\n", config_protocols->host); + printf("host: %s\n", sslhcfg_protocols->host); indent(depth); - printf("port: %s\n", config_protocols->port); + printf("port: %s\n", sslhcfg_protocols->port); indent(depth); - printf("service: %s\n", config_protocols->service); + printf("service: %s\n", sslhcfg_protocols->service); indent(depth); - printf("fork: %d\n", config_protocols->fork); + printf("fork: %d\n", sslhcfg_protocols->fork); indent(depth); - printf("log_level: %d\n", config_protocols->log_level); + printf("log_level: %d\n", sslhcfg_protocols->log_level); indent(depth); - printf("keepalive: %d\n", config_protocols->keepalive); + printf("keepalive: %d\n", sslhcfg_protocols->keepalive); indent(depth); - printf("sni_hostnames [%d]:\n", config_protocols->sni_hostnames_len); - for (i = 0; i < config_protocols->sni_hostnames_len; i++) { + printf("sni_hostnames [%d]:\n", sslhcfg_protocols->sni_hostnames_len); + for (i = 0; i < sslhcfg_protocols->sni_hostnames_len; i++) { indent(depth+1); - printf("%d:\t%s\n", i, config_protocols->sni_hostnames[i]); + printf("%d:\t%s\n", i, sslhcfg_protocols->sni_hostnames[i]); } indent(depth); - printf("alpn_protocols [%d]:\n", config_protocols->alpn_protocols_len); - for (i = 0; i < config_protocols->alpn_protocols_len; i++) { + printf("alpn_protocols [%d]:\n", sslhcfg_protocols->alpn_protocols_len); + for (i = 0; i < sslhcfg_protocols->alpn_protocols_len; i++) { indent(depth+1); - printf("%d:\t%s\n", i, config_protocols->alpn_protocols[i]); + printf("%d:\t%s\n", i, sslhcfg_protocols->alpn_protocols[i]); } indent(depth); - printf("regex_patterns [%d]:\n", config_protocols->regex_patterns_len); - for (i = 0; i < config_protocols->regex_patterns_len; i++) { + printf("regex_patterns [%d]:\n", sslhcfg_protocols->regex_patterns_len); + for (i = 0; i < sslhcfg_protocols->regex_patterns_len; i++) { indent(depth+1); - printf("%d:\t%s\n", i, config_protocols->regex_patterns[i]); + printf("%d:\t%s\n", i, sslhcfg_protocols->regex_patterns[i]); } - printf("\n"); } -static void config_listen_print( - struct config_listen_item* config_listen, +static void sslhcfg_listen_print( + struct sslhcfg_listen_item* sslhcfg_listen, int depth) { int i; indent(depth); - printf("host: %s\n", config_listen->host); + printf("host: %s\n", sslhcfg_listen->host); indent(depth); - printf("port: %s\n", config_listen->port); + printf("port: %s\n", sslhcfg_listen->port); indent(depth); - printf("keepalive: %d\n", config_listen->keepalive); - printf("\n"); + printf("keepalive: %d\n", sslhcfg_listen->keepalive); } -void config_print( - struct config_item* config, +void sslhcfg_print( + struct sslhcfg_item* sslhcfg, int depth) { int i; indent(depth); - printf("verbose: %d\n", config->verbose); + printf("verbose: %d\n", sslhcfg->verbose); indent(depth); - printf("foreground: %d\n", config->foreground); + printf("foreground: %d\n", sslhcfg->foreground); indent(depth); - printf("inetd: %d\n", config->inetd); + printf("inetd: %d\n", sslhcfg->inetd); indent(depth); - printf("numeric: %d\n", config->numeric); + printf("numeric: %d\n", sslhcfg->numeric); indent(depth); - printf("transparent: %d\n", config->transparent); + printf("transparent: %d\n", sslhcfg->transparent); indent(depth); - printf("timeout: %d\n", config->timeout); + printf("timeout: %d\n", sslhcfg->timeout); indent(depth); - printf("user: %s\n", config->user); + printf("user: %s\n", sslhcfg->user); indent(depth); - printf("pidfile: %s\n", config->pidfile); + printf("pidfile: %s\n", sslhcfg->pidfile); indent(depth); - printf("chroot: %s\n", config->chroot); + printf("chroot: %s\n", sslhcfg->chroot); indent(depth); - printf("syslog_facility: %s\n", config->syslog_facility); + printf("syslog_facility: %s\n", sslhcfg->syslog_facility); indent(depth); - printf("on_timeout: %s\n", config->on_timeout); + printf("on_timeout: %s\n", sslhcfg->on_timeout); indent(depth); - printf("listen [%d]:\n", config->listen_len); - for (int i = 0; i < config->listen_len; i++) { - config_listen_print(&config->listen[i], depth+1); + printf("listen [%d]:\n", sslhcfg->listen_len); + for (int i = 0; i < sslhcfg->listen_len; i++) { + sslhcfg_listen_print(&sslhcfg->listen[i], depth+1); } indent(depth); - printf("protocols [%d]:\n", config->protocols_len); - for (int i = 0; i < config->protocols_len; i++) { - config_protocols_print(&config->protocols[i], depth+1); + printf("protocols [%d]:\n", sslhcfg->protocols_len); + for (int i = 0; i < sslhcfg->protocols_len; i++) { + sslhcfg_protocols_print(&sslhcfg->protocols[i], depth+1); } - printf("\n"); } diff --git a/sslh-conf.h b/sslh-conf.h index 28efd4b..f0d4046 100644 --- a/sslh-conf.h +++ b/sslh-conf.h @@ -1,9 +1,9 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct) - * on Mon Dec 3 10:48:52 2018. */ + * on Tue Dec 4 21:49:45 2018. */ -#ifndef C2S_CONFIG_H -#define C2S_CONFIG_H +#ifndef C2S_SSLHCFG_H +#define C2S_SSLHCFG_H #include #include "probe.h" @@ -11,13 +11,13 @@ #include #include -struct config_listen_item { +struct sslhcfg_listen_item { char* host; char* port; int keepalive; }; -struct config_protocols_item { +struct sslhcfg_protocols_item { const char* name; char* host; char* port; @@ -37,7 +37,7 @@ struct config_protocols_item { void* data; }; -struct config_item { +struct sslhcfg_item { int verbose; int foreground; int inetd; @@ -53,18 +53,18 @@ struct config_item { const char* syslog_facility; const char* on_timeout; size_t listen_len; - struct config_listen_item* listen; + struct sslhcfg_listen_item* listen; size_t protocols_len; - struct config_protocols_item* protocols; + struct sslhcfg_protocols_item* protocols; }; -int config_parse_file( +int sslhcfg_parse_file( const char* filename, - struct config_item* config, + struct sslhcfg_item* sslhcfg, const char** errmsg); -void config_print( - struct config_item *config, +void sslhcfg_print( + struct sslhcfg_item *sslhcfg, int depth); #endif diff --git a/sslh-main.c b/sslh-main.c index 80a2927..b61ead8 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -81,16 +81,14 @@ static struct option const_options[] = { }; */ static struct option* all_options; -#if 0 -static struct config_protocols_item* builtins; -#endif +static struct sslhcfg_protocols_item* builtins; static const char *optstr = "vt:T:p:VP:C:F::"; static void print_usage(void) { - struct config_protocols_item *p; + struct sslhcfg_protocols_item *p; int i; int res; char *prots = ""; @@ -126,7 +124,7 @@ static void printsettings(void) char buf[NI_MAXHOST]; struct addrinfo *a; int i; - struct config_protocols_item *p; + struct sslhcfg_protocols_item *p; for (i = 0; i < cfg.protocols_len; i++ ) { p = &cfg.protocols[i]; @@ -201,164 +199,40 @@ static int config_resolve_listen(struct addrinfo **listen) } return 0; } - -#if 0 -static int config_listen(config_t *config, struct addrinfo **listen) -{ - config_setting_t *setting, *addr; - int len, i, keepalive; - const char *hostname, *port; - - setting = config_lookup(config, "listen"); - if (setting) { - len = config_setting_length(setting); - for (i = 0; i < len; i++) { - addr = config_setting_get_elem(setting, i); - if (! (config_setting_lookup_string(addr, "host", &hostname) && - config_setting_lookup_string(addr, "port", &port))) { - fprintf(stderr, - "line %d:Incomplete specification (hostname and port required)\n", - config_setting_source_line(addr)); - return -1; - } - - keepalive = 0; - config_setting_lookup_bool(addr, "keepalive", &keepalive); - - resolve_split_name(listen, hostname, port); - - /* getaddrinfo returned a list of addresses corresponding to the - * specification; move the pointer to the end of that list before - * processing the next specification, while setting flags for - * start_listen_sockets() through ai_flags (which is not meant for - * that, but is only used as hint in getaddrinfo, so it's OK) */ - for (; *listen; listen = &((*listen)->ai_next)) { - if (keepalive) - (*listen)->ai_flags = SO_KEEPALIVE; - } - } - } - - return 0; -} -#endif #endif #ifdef LIBCONFIG -static void setup_regex_probe(struct config_protocols_item *p, config_setting_t* probes) +static void setup_regex_probe(struct sslhcfg_protocols_item *p) { -#ifdef ENABLE_REGEX - int num_probes, errsize, i, res; - char *err; - const char * expr; - regex_t** probe_list; + int num_patterns, i, res; + regex_t** pattern_list; + size_t errsize; + char* err; - num_probes = config_setting_length(probes); - if (!num_probes) { - fprintf(stderr, "%s: no probes specified\n", p->name); - exit(1); - } + num_patterns = p->regex_patterns_len; - p->probe = get_probe("regex"); - probe_list = calloc(num_probes + 1, sizeof(*probe_list)); - CHECK_ALLOC(probe_list, "calloc"); - p->data = (void*)probe_list; + pattern_list = calloc(num_patterns + 1, sizeof(*pattern_list)); + CHECK_ALLOC(pattern_list, "calloc"); + p->data = (void*)pattern_list; - for (i = 0; i < num_probes; i++) { - probe_list[i] = malloc(sizeof(*(probe_list[i]))); - CHECK_ALLOC(probe_list[i], "malloc"); - expr = config_setting_get_string_elem(probes, i); - if (expr == NULL) { - fprintf(stderr, "%s: invalid probe specified\n", p->name); - exit(1); - } - res = regcomp(probe_list[i], expr, REG_EXTENDED); + for (i = 0; i < num_patterns; i++) { + pattern_list[i] = malloc(sizeof(*(pattern_list[i]))); + CHECK_ALLOC(pattern_list[i], "malloc"); + res = regcomp(pattern_list[i], p->regex_patterns[i], REG_EXTENDED); if (res) { - err = malloc(errsize = regerror(res, probe_list[i], NULL, 0)); + err = malloc(errsize = regerror(res, pattern_list[i], NULL, 0)); CHECK_ALLOC(err, "malloc"); - regerror(res, probe_list[i], err, errsize); - fprintf(stderr, "%s:%s\n", expr, err); + regerror(res, pattern_list[i], err, errsize); + fprintf(stderr, "%s:%s\n", pattern_list[i], err); free(err); exit(1); } } -#else - fprintf(stderr, "line %d: regex probe specified but not compiled in\n", config_setting_source_line(probes)); - exit(5); -#endif } #endif -#ifdef LIBCONFIG -#if 0 -static void setup_sni_alpn_list( - struct config_protocols_item *p, - config_setting_t* config_items, - const char* name, - int alpn) -{ - int num_probes, i, max_server_name_len, server_name_len; - const char * config_item, *server_name; - char** sni_hostname_list; - - num_probes = config_setting_length(config_items); - if (!num_probes) { - fprintf(stderr, "%s: no %s specified\n", p->description, name); - return; - } - - max_server_name_len = 0; - for (i = 0; i < num_probes; i++) { - server_name = config_setting_get_string_elem(config_items, i); - if (server_name == NULL) { - fprintf(stderr, "%s: invalid %s specified\n", p->description, name); - exit(1); - } - server_name_len = strlen(server_name); - if(server_name_len > max_server_name_len) - max_server_name_len = server_name_len; - } - - sni_hostname_list = calloc(num_probes + 1, ++max_server_name_len); - CHECK_ALLOC(sni_hostname_list, "calloc"); - - for (i = 0; i < num_probes; i++) { - config_item = config_setting_get_string_elem(config_items, i); - if (config_item == NULL) { - fprintf(stderr, "%s: invalid %s specified\n", p->description, name); - exit(1); - } - sni_hostname_list[i] = malloc(max_server_name_len); - CHECK_ALLOC(sni_hostname_list[i], "malloc"); - strcpy (sni_hostname_list[i], config_item); - if(verbose) fprintf(stderr, "%s: %s[%d]: %s\n", p->description, name, i, sni_hostname_list[i]); - } - - p->data = (void*)tls_data_set_list(p->data, alpn, sni_hostname_list); -} - -static void setup_sni_alpn(struct config_protocols_item *p, config_setting_t* prot) -{ - config_setting_t *sni_hostnames, *alpn_protocols; - - p->data = (void*)new_tls_data(); - sni_hostnames = config_setting_get_member(prot, "sni_hostnames"); - alpn_protocols = config_setting_get_member(prot, "alpn_protocols"); - - if(sni_hostnames && config_setting_is_array(sni_hostnames)) { - setup_sni_alpn_list(p, sni_hostnames, "sni_hostnames", 0); - } - if(alpn_protocols && config_setting_is_array(alpn_protocols)) { - setup_sni_alpn_list(p, alpn_protocols, "alpn_protocols", 1); - } -} -#endif -static void setup_sni_alpn(struct config_protocols_item *p, config_setting_t* prot) -{} -#endif - /* For each protocol in the configuration, resolve address and set up protocol * options if required */ @@ -367,7 +241,7 @@ static int config_protocols() { int i; for (i = 0; i < cfg.protocols_len; i++) { - struct config_protocols_item* p = &(cfg.protocols[i]); + struct sslhcfg_protocols_item* p = &(cfg.protocols[i]); if (resolve_split_name(&(p->saddr), p->host, p->port)) { fprintf(stderr, "cannot resolve %s:%s\n", p->host, p->port); exit(1); @@ -379,6 +253,10 @@ static int config_protocols() exit(1); } + if (!strcmp(cfg.protocols[i].name, "regex")) { + setup_regex_probe(&cfg.protocols[i]); + } + if (!strcmp(cfg.protocols[i].name, "tls")) { cfg.protocols[i].data = (void*)new_tls_data(); if (cfg.protocols[i].sni_hostnames_len) @@ -392,93 +270,20 @@ static int config_protocols() } } } - -#if 0 -static int config_protocols(config_t *config, struct proto **prots) -{ - config_setting_t *setting, *prot, *patterns; - const char *hostname, *port, *cfg_name; - char* name; - int i, num_prots; - struct proto *p, *prev = NULL; - - setting = config_lookup(config, "protocols"); - if (setting) { - num_prots = config_setting_length(setting); - for (i = 0; i < num_prots; i++) { - p = calloc(1, sizeof(*p)); - CHECK_ALLOC(p, "calloc"); - if (i == 0) *prots = p; - if (prev) prev->next = p; - prev = p; - - prot = config_setting_get_elem(setting, i); - if ((config_setting_lookup_string(prot, "name", &cfg_name) && - config_setting_lookup_string(prot, "host", &hostname) && - config_setting_lookup_string(prot, "port", &port) - )) { - /* To removed in v1.21 */ - name = strdup(cfg_name); - ssl_to_tls(name); - /* /remove */ - p->description = name; - config_setting_lookup_string(prot, "service", &(p->service)); - config_setting_lookup_bool(prot, "keepalive", &p->keepalive); - config_setting_lookup_bool(prot, "fork", &p->fork); - - if (config_setting_lookup_int(prot, "log_level", &p->log_level) == CONFIG_FALSE) { - p->log_level = 1; - } - - if (resolve_split_name(&(p->saddr), hostname, port)) { - fprintf(stderr, "line %d: cannot resolve %s:%s\n", config_setting_source_line(prot), hostname, port); - exit(1); - } - - p->probe = get_probe(name); - if (!p->probe) { - fprintf(stderr, "line %d: %s: probe unknown\n", config_setting_source_line(prot), name); - exit(1); - } - - /* Probe-specific options: regex patterns */ - if (!strcmp(name, "regex")) { - patterns = config_setting_get_member(prot, "regex_patterns"); - if (patterns && config_setting_is_array(patterns)) { - setup_regex_probe(p, patterns); - } - } - - /* Probe-specific options: SNI/ALPN */ - if (!strcmp(name, "tls")) { - setup_sni_alpn(p, prot); - } - - } else { - fprintf(stderr, "line %d: Illegal protocol description (missing name, host or port)\n", config_setting_source_line(prot)); - exit(1); - } - } - } - - return 0; -} -#endif #endif /* Parses a config file * in: *filename * out: *listen, a newly-allocated linked list of listen addrinfo - * *prots, a newly-allocated linked list of protocols * 1 on error, 0 on success */ #ifdef LIBCONFIG -static int config_parse(char *filename, struct addrinfo **listen, struct config_protocols_item **prots) +static int config_parse(char *filename, struct addrinfo **listen) { int res; const char* err; - if (!config_parse_file(filename, &cfg, &err)) { + if (!sslhcfg_parse_file(filename, &cfg, &err)) { fprintf(stderr, err); return 1; } @@ -486,11 +291,6 @@ static int config_parse(char *filename, struct addrinfo **listen, struct config_ config_resolve_listen(listen); config_protocols(); - /* - config_listen(&config, listen); - config_protocols(&config, prots); - */ - return 0; } #endif @@ -502,7 +302,7 @@ static int config_parse(char *filename, struct addrinfo **listen, struct config_ * prot: array of protocols * n_prots: number of protocols in *prot * */ -static void append_protocols(struct option *options, int n_opts, struct config_protocols_item *prot , int n_prots) +static void append_protocols(struct option *options, int n_opts, struct sslhcfg_protocols_item *prot , int n_prots) { int o, p; @@ -534,7 +334,7 @@ static void make_alloptions(void) * * prots: newly-allocated list of configured protocols, if any. */ -static void cmdline_config(int argc, char* argv[], struct config_protocols_item** prots) +static void cmdline_config(int argc, char* argv[], struct sslhcfg_protocols_item** prots) { #ifdef LIBCONFIG int c, res; @@ -555,13 +355,13 @@ static void cmdline_config(int argc, char* argv[], struct config_protocols_item* if (c == 'F') { config_filename = optarg; if (config_filename) { - res = config_parse(config_filename, &addr_listen, prots); + res = config_parse(config_filename, &addr_listen); } else { /* No configuration file specified -- try default file locations */ - res = config_parse("/etc/sslh/sslh.cfg", &addr_listen, prots); + res = config_parse("/etc/sslh/sslh.cfg", &addr_listen); if (!res && cfg.verbose) fprintf(stderr, "Using /etc/sslh/sslh.cfg\n"); if (res) { - res = config_parse("/etc/sslh.cfg", &addr_listen, prots); + res = config_parse("/etc/sslh.cfg", &addr_listen); if (!res && cfg.verbose) fprintf(stderr, "Using /etc/sslh.cfg\n"); } } @@ -576,12 +376,12 @@ static void cmdline_config(int argc, char* argv[], struct config_protocols_item* /* Parse command-line options. prots points to a list of configured protocols, * potentially non-allocated */ -static void parse_cmdline(int argc, char* argv[], struct config_protocols_item* prots) +static void parse_cmdline(int argc, char* argv[], struct sslhcfg_protocols_item* prots) { #if 0 int c; struct addrinfo **a; - struct config_protocols_item *p; + struct sslhcfg_protocols_item *p; int background; optind = 1; @@ -700,7 +500,7 @@ int main(int argc, char *argv[]) extern char *optarg; extern int optind; int res, num_addr_listen; - struct config_protocols_item* protocols = NULL; + struct sslhcfg_protocols_item* protocols = NULL; int *listen_sockets; diff --git a/sslhconf.cfg b/sslhconf.cfg index 68db55c..684d120 100644 --- a/sslhconf.cfg +++ b/sslhconf.cfg @@ -12,7 +12,7 @@ includes: ( ); config: { - name : "config", + name : "sslhcfg", type: "list", items: ( { name: "verbose"; type: "int"; default: 0; }, @@ -26,7 +26,7 @@ config: { { name: "chroot"; type: "string"; optional: true; }, { name: "syslog_facility"; type: "string"; default: "auth"; }, - {name: "on_timeout"; type: "string"; default: "ssh"; }, + {name: "on-timeout"; type: "string"; default: "ssh"; }, { name: "listen", type: "list", diff --git a/t b/t index c9e4167..2aa4101 100755 --- a/t +++ b/t @@ -21,21 +21,21 @@ my $sslh_port = $conf->fetch_array("listen")->[0]->{port}; my $user = (getpwuid $<)[0]; # Run under current username # Which tests do we run -my $SSH_SHY_CNX = 1; +my $SSH_SHY_CNX = 0; my $PROBES_NOFRAG = 1; -my $PROBES_AGAIN = 1; -my $SSL_MIX_SSH = 1; -my $SSH_MIX_SSL = 1; +my $PROBES_AGAIN = 0; +my $SSL_MIX_SSH = 0; +my $SSH_MIX_SSL = 0; # Robustness tests. These are mostly to achieve full test # coverage, but do not necessarily result in an actual test # (e.g. some tests need to be run with valgrind to check all # memory management code). -my $RB_CNX_NOSERVER = 1; -my $RB_PARAM_NOHOST = 1; -my $RB_WRONG_USERNAME = 1; -my $RB_OPEN_PID_FILE = 1; -my $RB_RESOLVE_ADDRESS = 1; +my $RB_CNX_NOSERVER = 0; +my $RB_PARAM_NOHOST = 0; +my $RB_WRONG_USERNAME = 0; +my $RB_OPEN_PID_FILE = 0; +my $RB_RESOLVE_ADDRESS = 0; `lcov --directory . --zerocounters`; @@ -161,6 +161,16 @@ sub test_probes { ); } } + } elsif ($p->{name} eq 'regex') { + foreach my $pattern (@{$p->{regex_patterns}}) { + $pattern =~ /(\w+)/; + my $out = $1; + test_probe( + data => $out, + expected => $p->{name}, + %opts + ); + } } else { test_probe( data => $pattern, diff --git a/test.cfg b/test.cfg index f468683..55a5e53 100644 --- a/test.cfg +++ b/test.cfg @@ -30,6 +30,9 @@ protocols: { name: "openvpn"; host: "localhost"; port: "9004"; }, { name: "xmpp"; host: "localhost"; port: "9009"; }, { name: "adb"; host: "localhost"; port: "9010"; }, + { name: "regex"; host: "localhost"; port: "9011"; + regex_patterns: [ "^foo", "^bar" ]; + }, { name: "tls"; host: "localhost"; port: "9021"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni1" ]; }, { name: "tls"; host: "localhost"; port: "9022"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni2", "sni3" ]; }, { name: "tls"; host: "localhost"; port: "9023"; alpn_protocols: [ "alpn3" ]; }, From ad0adfb0e1fb423c312eca11aa135d8afcb4c484 Mon Sep 17 00:00:00 2001 From: yrutschle Date: Fri, 7 Dec 2018 08:32:36 +0100 Subject: [PATCH 4/5] re-integrate command line support --- common.c | 2 +- probe.c | 27 +++-------------- probe.h | 29 +++++------------- sslh-conf.c | 2 +- sslh-conf.h | 2 +- sslh-main.c | 86 +++++++++++++++++++++++------------------------------ 6 files changed, 52 insertions(+), 96 deletions(-) diff --git a/common.c b/common.c index 0c5244e..bc405b6 100644 --- a/common.c +++ b/common.c @@ -355,7 +355,7 @@ void init_cnx(struct connection *cnx) memset(cnx, 0, sizeof(*cnx)); cnx->q[0].fd = -1; cnx->q[1].fd = -1; - cnx->proto = get_first_protocol(); + cnx->proto = NULL; } void dump_connection(struct connection *cnx) diff --git a/probe.c b/probe.c index ca4c152..aaf4ac8 100644 --- a/probe.c +++ b/probe.c @@ -43,11 +43,6 @@ static int is_adb_protocol(const char *p, int len, struct sslhcfg_protocols_item static int is_socks5_protocol(const char *p, int len, struct sslhcfg_protocols_item*); static int is_true(const char *p, int len, struct sslhcfg_protocols_item* proto) { return 1; } -struct protocol_probe_desc { - const char* name; - T_PROBE* probe; -}; - /* Table of protocols that have a built-in probe */ static struct protocol_probe_desc builtins[] = { @@ -64,12 +59,11 @@ static struct protocol_probe_desc builtins[] = { { "anyprot", is_true } }; -static struct sslhcfg_protocols_item *protocols; static char* on_timeout = "ssh"; /* TODO I think this has to go */ -struct sslhcfg_protocols_item* get_builtins(void) { - return NULL; +struct protocol_probe_desc* get_builtins(void) { + return builtins; } int get_num_builtins(void) { @@ -90,24 +84,11 @@ struct sslhcfg_protocols_item* timeout_protocol(void) { int i; for (i = 0; i < cfg.protocols_len; i++) { - printf("prot %d:%s vs %s\n",i, cfg.protocols[i].name, on_timeout); if (!strcmp(cfg.protocols[i].name, on_timeout)) return &cfg.protocols[i]; } - return get_first_protocol(); + return &cfg.protocols[0]; } -/* returns the first protocol (caller can then follow the *next pointers) */ -struct sslhcfg_protocols_item* get_first_protocol(void) -{ - return protocols; -} - -void set_protocol_list(struct sslhcfg_protocols_item* prots) -{ -#if 0 - protocols = prots; -#endif -} /* From http://grapsus.net/blog/post/Hexadecimal-dump-in-C */ #define HEXDUMP_COLS 16 @@ -355,7 +336,7 @@ static int regex_probe(const char *p, int len, struct sslhcfg_protocols_item* pr int probe_client_protocol(struct connection *cnx) { char buffer[BUFSIZ]; - struct sslhcfg_protocols_item* p, *last_p = cnx->proto; + struct sslhcfg_protocols_item* p; int i, n, res, again = 0; n = read(cnx->q[0].fd, buffer, sizeof(buffer)); diff --git a/probe.h b/probe.h index 7119789..5ee199c 100644 --- a/probe.h +++ b/probe.h @@ -15,31 +15,16 @@ typedef enum { struct sslhcfg_protocols_item; typedef int T_PROBE(const char*, int, struct sslhcfg_protocols_item*); +struct protocol_probe_desc { + const char* name; + T_PROBE* probe; +}; + + #include "sslh-conf.h" -/* For each protocol we need: */ -#if 0 -struct proto { - const char* description; /* a string that says what it is (for logging and command-line parsing) */ - const char* service; /* service name to do libwrap checks */ - struct addrinfo *saddr; /* list of addresses to try and switch that protocol */ - int log_level; /* 0: No logging of connection - * 1: Log incoming connection - */ - int keepalive; /* 0: No keepalive ; 1: Set Keepalive for this connection */ - int fork; /* 0: Connection can run within shared process ; 1: Separate process required for this connection */ - - /* function to probe that protocol; parameters are buffer and length - * containing the data to probe, and a pointer to the protocol structure */ - T_PROBE* probe; - /* opaque pointer ; used to pass list of regex to regex probe, or TLSProtocol struct to sni/alpn probe */ - void* data; - struct proto *next; /* pointer to next protocol in list, NULL if last */ -}; -#endif - /* Returns a pointer to the array of builtin protocols */ -struct sslhcfg_protocols_item* get_builtins(void); +struct protocol_probe_desc* get_builtins(void); /* Returns the number of builtin protocols */ int get_num_builtins(void); diff --git a/sslh-conf.c b/sslh-conf.c index e4fecdf..c5afa62 100644 --- a/sslh-conf.c +++ b/sslh-conf.c @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct) - * on Tue Dec 4 21:49:45 2018. */ + * on Fri Dec 7 08:27:14 2018. */ diff --git a/sslh-conf.h b/sslh-conf.h index f0d4046..9b1a3d8 100644 --- a/sslh-conf.h +++ b/sslh-conf.h @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct) - * on Tue Dec 4 21:49:45 2018. */ + * on Fri Dec 7 08:27:14 2018. */ #ifndef C2S_SSLHCFG_H diff --git a/sslh-main.c b/sslh-main.c index b61ead8..4c715c2 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -62,14 +62,12 @@ const char* USAGE_STRING = /* Constants for options that have no one-character shorthand */ #define OPT_ONTIMEOUT 257 - /* static struct option const_options[] = { - { "inetd", no_argument, &inetd, 1 }, - { "foreground", no_argument, &foreground, 1 }, - { "background", no_argument, &background, 1 }, - { "transparent", no_argument, &transparent, 1 }, - { "numeric", no_argument, &numeric, 1 }, - { "verbose", no_argument, &verbose, 1 }, + { "inetd", no_argument, &cfg.inetd, 1 }, + { "foreground", no_argument, &cfg.foreground, 1 }, + { "transparent", no_argument, &cfg.transparent, 1 }, + { "numeric", no_argument, &cfg.numeric, 1 }, + { "verbose", no_argument, &cfg.verbose, 1 }, { "user", required_argument, 0, 'u' }, { "config", optional_argument, 0, 'F' }, { "pidfile", required_argument, 0, 'P' }, @@ -79,16 +77,16 @@ static struct option const_options[] = { { "listen", required_argument, 0, 'p' }, {} }; - */ + static struct option* all_options; -static struct sslhcfg_protocols_item* builtins; +static struct protocol_probe_desc* builtins; static const char *optstr = "vt:T:p:VP:C:F::"; static void print_usage(void) { - struct sslhcfg_protocols_item *p; + struct protocol_probe_desc *p; int i; int res; char *prots = ""; @@ -302,7 +300,7 @@ static int config_parse(char *filename, struct addrinfo **listen) * prot: array of protocols * n_prots: number of protocols in *prot * */ -static void append_protocols(struct option *options, int n_opts, struct sslhcfg_protocols_item *prot , int n_prots) +static void append_protocols(struct option *options, int n_opts, struct protocol_probe_desc* prot , int n_prots) { int o, p; @@ -316,7 +314,6 @@ static void append_protocols(struct option *options, int n_opts, struct sslhcfg_ static void make_alloptions(void) { -#if 0 builtins = get_builtins(); /* Create all_options, composed of const_options followed by one option per @@ -325,7 +322,6 @@ static void make_alloptions(void) CHECK_ALLOC(all_options, "calloc"); memcpy(all_options, const_options, sizeof(const_options)); append_protocols(all_options, ARRAY_SIZE(const_options) - 1, builtins, get_num_builtins()); -#endif } /* Performs a first scan of command line options to see if a configuration file @@ -378,11 +374,9 @@ static void cmdline_config(int argc, char* argv[], struct sslhcfg_protocols_item * potentially non-allocated */ static void parse_cmdline(int argc, char* argv[], struct sslhcfg_protocols_item* prots) { -#if 0 int c; struct addrinfo **a; - struct sslhcfg_protocols_item *p; - int background; + int background, i; optind = 1; opterr = 1; @@ -391,29 +385,25 @@ next_arg: if (c == 0) continue; if (c >= PROT_SHIFT) { - if (prots) - for (p = prots; p && p->next; p = p->next) { - /* override if protocol was already defined by config file - * (note it only overrides address and use builtin probe) */ - if (!strcmp(p->name, builtins[c-PROT_SHIFT].name)) { - resolve_name(&(p->saddr), optarg); - p->probe = builtins[c-PROT_SHIFT].probe; - goto next_arg; - } + int prot_num = c - PROT_SHIFT; + for (i = 0; i < cfg.protocols_len; i++) { + /* override if protocol was already defined by config file */ + if (!strcmp(cfg.protocols[i].name, builtins[prot_num].name)) { + resolve_name(&(cfg.protocols[i].saddr), optarg); + goto next_arg; } + } /* At this stage, it's a new protocol: add it to the end of the * list */ - if (!prots) { - /* No protocols yet -- create the list */ - p = prots = calloc(1, sizeof(*p)); - CHECK_ALLOC(p, "calloc"); - } else { - p->next = calloc(1, sizeof(*p)); - CHECK_ALLOC(p->next, "calloc"); - p = p->next; - } - memcpy(p, &builtins[c-PROT_SHIFT], sizeof(*p)); - resolve_name(&(p->saddr), optarg); + cfg.protocols_len++; + cfg.protocols = realloc(cfg.protocols, cfg.protocols_len * sizeof(*cfg.protocols)); + CHECK_ALLOC(cfg.protocols, "realloc"); + + /* set up name, target and probe. everything else defaults to 0 */ + memset(&cfg.protocols[cfg.protocols_len-1], 0, sizeof(cfg.protocols[0])); + cfg.protocols[cfg.protocols_len-1].probe = get_probe(builtins[prot_num].name); + cfg.protocols[cfg.protocols_len-1].name = builtins[prot_num].name; + resolve_name(&cfg.protocols[cfg.protocols_len-1].saddr, optarg); continue; } @@ -422,12 +412,14 @@ next_arg: case 'F': /* Legal option, but do nothing, it was already processed in * cmdline_config() */ +#ifndef LIBCONFIG fprintf(stderr, "Built without libconfig support: configuration file not available.\n"); exit(1); +#endif break; case 't': - probing_timeout = atoi(optarg); + cfg.timeout = atoi(optarg); break; case OPT_ONTIMEOUT: @@ -447,19 +439,19 @@ next_arg: exit(0); case 'u': - user_name = optarg; + cfg.user = optarg; break; case 'P': - pid_file = optarg; + cfg.pidfile = optarg; break; case 'C': - chroot_path = optarg; + cfg.chroot = optarg; break; case 'v': - verbose++; + cfg.verbose++; break; default: @@ -470,15 +462,11 @@ next_arg: return; - if (!prots) { + if (!cfg.protocols_len) { fprintf(stderr, "At least one target protocol must be specified.\n"); exit(2); } - /* - set_protocol_list(prots); - */ - /* If compiling with systemd socket support no need to require listen address */ #ifndef SYSTEMD if (!addr_listen && !cfg.inetd) { @@ -491,7 +479,6 @@ next_arg: if (background) cfg.foreground = 0; -#endif } int main(int argc, char *argv[]) @@ -504,10 +491,13 @@ int main(int argc, char *argv[]) int *listen_sockets; - /* Init defaults */ + /* Init defaults -- conf2struct sets them when parsing a config file + * but we may configure entirely from the command line */ cfg.pidfile = NULL; cfg.user = NULL; cfg.chroot = NULL; + cfg.syslog_facility = "auth"; + cfg.timeout = 2; cmdline_config(argc, argv, &protocols); parse_cmdline(argc, argv, protocols); From 343b0a0fbf359e0806873bdf9cae0d140e1f2e35 Mon Sep 17 00:00:00 2001 From: yrutschle Date: Fri, 7 Dec 2018 08:40:30 +0100 Subject: [PATCH 5/5] reactivate tests --- t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t b/t index 2aa4101..057e4d5 100755 --- a/t +++ b/t @@ -21,11 +21,11 @@ my $sslh_port = $conf->fetch_array("listen")->[0]->{port}; my $user = (getpwuid $<)[0]; # Run under current username # Which tests do we run -my $SSH_SHY_CNX = 0; +my $SSH_SHY_CNX = 1; my $PROBES_NOFRAG = 1; -my $PROBES_AGAIN = 0; -my $SSL_MIX_SSH = 0; -my $SSH_MIX_SSL = 0; +my $PROBES_AGAIN = 1; +my $SSL_MIX_SSH = 1; +my $SSH_MIX_SSL = 1; # Robustness tests. These are mostly to achieve full test # coverage, but do not necessarily result in an actual test