From 067f5d76462e26cdbcb898425cc35453f21df232 Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Sun, 8 Jan 2017 12:54:34 +0100 Subject: [PATCH 01/10] Revert "clarify no space after -F (issue 108)" This reverts commit f02ce3821c018719536971dbb1bc1ed1517530a2. That commit accidently imported code that broke transparent proxying. --- common.c | 5 +++-- common.h | 3 ++- probe.c | 20 ++++++++++---------- probe.h | 1 - sslh-main.c | 18 ++++++------------ sslh.pod | 7 ++----- 6 files changed, 23 insertions(+), 31 deletions(-) diff --git a/common.c b/common.c index 8187b4d..394cdb1 100644 --- a/common.c +++ b/common.c @@ -37,6 +37,7 @@ 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; @@ -236,7 +237,7 @@ 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 (cnx->proto->transparent && a->ai_family != from.ai_addr->sa_family) + if (transparent && a->ai_family != from.ai_addr->sa_family) continue; if (verbose) fprintf(stderr, "connecting to %s family %d len %d\n", @@ -249,7 +250,7 @@ int connect_addr(struct connection *cnx, int fd_from) log_message(LOG_ERR, "forward to %s failed:socket: %s\n", cnx->proto->description, strerror(errno)); } else { - if (cnx->proto->transparent) { + if (transparent) { res = bind_peer(fd, fd_from); CHECK_RES_RETURN(res, "bind_peer"); } diff --git a/common.h b/common.h index 1002d23..701b337 100644 --- a/common.h +++ b/common.h @@ -113,7 +113,8 @@ int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list); int defer_write(struct queue *q, void* data, int data_size); int flush_deferred(struct queue *q); -extern int probing_timeout, verbose, inetd, foreground, background, numeric; +extern int probing_timeout, verbose, inetd, foreground, + background, transparent, numeric; 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 22bdc3b..9b4a63e 100644 --- a/probe.c +++ b/probe.c @@ -45,16 +45,16 @@ static int is_true(const char *p, int len, struct proto* proto) { return 1; } /* Table of protocols that have a built-in probe */ static struct proto builtins[] = { - /* description service saddr log_level keepalive transparent probe */ - { "ssh", "sshd", NULL, 1, 0, 0, is_ssh_protocol}, - { "openvpn", NULL, NULL, 1, 0, 0, is_openvpn_protocol }, - { "tinc", NULL, NULL, 1, 0, 0, is_tinc_protocol }, - { "xmpp", NULL, NULL, 1, 0, 0, is_xmpp_protocol }, - { "http", NULL, NULL, 1, 0, 0, is_http_protocol }, - { "ssl", NULL, NULL, 1, 0, 0, is_tls_protocol }, - { "tls", NULL, NULL, 1, 0, 0, is_tls_protocol }, - { "adb", NULL, NULL, 1, 0, 0, is_adb_protocol }, - { "anyprot", NULL, NULL, 1, 0, 0, is_true } + /* description service saddr log_level keepalive probe */ + { "ssh", "sshd", NULL, 1, 0, is_ssh_protocol}, + { "openvpn", NULL, NULL, 1, 0, is_openvpn_protocol }, + { "tinc", NULL, NULL, 1, 0, is_tinc_protocol }, + { "xmpp", NULL, NULL, 1, 0, is_xmpp_protocol }, + { "http", NULL, NULL, 1, 0, is_http_protocol }, + { "ssl", NULL, NULL, 1, 0, is_tls_protocol }, + { "tls", NULL, NULL, 1, 0, is_tls_protocol }, + { "adb", NULL, NULL, 1, 0, is_adb_protocol }, + { "anyprot", NULL, NULL, 1, 0, is_true } }; static struct proto *protocols; diff --git a/probe.h b/probe.h index 492e42f..8c576a2 100644 --- a/probe.h +++ b/probe.h @@ -24,7 +24,6 @@ struct proto { * 1: Log incoming connection */ int keepalive; /* 0: No keepalive ; 1: Set Keepalive for this connection */ - int transparent; /* 0: opaque proxy ; 1: transparent proxy */ /* function to probe that protocol; parameters are buffer and length * containing the data to probe, and a pointer to the protocol structure */ diff --git a/sslh-main.c b/sslh-main.c index b72a2c0..3242cc4 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -39,7 +39,7 @@ const char* USAGE_STRING = "sslh " VERSION "\n" \ "usage:\n" \ -"\tsslh [-v] [-i] [-V] [-f] [-n] [--transparent] [-F]\n" +"\tsslh [-v] [-i] [-V] [-f] [-n] [--transparent] [-F ]\n" "\t[-t ] [-P ] -u -p [-p ...] \n" \ "%s\n\n" /* Dynamically built list of builtin protocols */ \ "\t[--on-timeout ]\n" \ @@ -49,7 +49,7 @@ const char* USAGE_STRING = "-n: numeric output\n" \ "-u: specify under which user to run\n" \ "--transparent: behave as a transparent proxy\n" \ -"-F: use configuration file (warning: no space between -F and file name!)\n" \ +"-F: use configuration file\n" \ "--on-timeout: connect to specified address upon timeout (default: ssh address)\n" \ "-t: seconds to wait before connecting to --on-timeout address.\n" \ "-p: address and port to listen on.\n Can be used several times to bind to several addresses.\n" \ @@ -61,14 +61,11 @@ const char* USAGE_STRING = /* Constants for options that have no one-character shorthand */ #define OPT_ONTIMEOUT 257 -/* Global setting for transparent proxying */ -int g_transparent = 0; - static struct option const_options[] = { { "inetd", no_argument, &inetd, 1 }, { "foreground", no_argument, &foreground, 1 }, { "background", no_argument, &background, 1 }, - { "transparent", no_argument, &g_transparent, 1 }, + { "transparent", no_argument, &transparent, 1 }, { "numeric", no_argument, &numeric, 1 }, { "verbose", no_argument, &verbose, 1 }, { "user", required_argument, 0, 'u' }, @@ -126,16 +123,14 @@ static void printsettings(void) for (p = get_first_protocol(); p; p = p->next) { fprintf(stderr, - "%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s%s]\n", + "%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s]\n", p->description, sprintaddr(buf, sizeof(buf), p->saddr), p->service, p->log_level, p->saddr->ai_family, p->saddr->ai_addr->sa_family, - p->keepalive ? "keepalive " : "", - p->transparent ? "transparent" : "" - ); + p->keepalive ? "keepalive" : ""); } fprintf(stderr, "listening on:\n"); for (a = addr_listen; a; a = a->ai_next) { @@ -312,7 +307,6 @@ static int config_protocols(config_t *config, struct proto **prots) p->description = name; config_setting_lookup_string(prot, "service", &(p->service)); config_setting_lookup_bool(prot, "keepalive", &p->keepalive); - config_setting_lookup_bool(prot, "transparent", &p->transparent); if (config_setting_lookup_int(prot, "log_level", &p->log_level) == CONFIG_FALSE) { p->log_level = 1; @@ -382,7 +376,7 @@ static int config_parse(char *filename, struct addrinfo **listen, struct proto * config_lookup_bool(&config, "inetd", &inetd); config_lookup_bool(&config, "foreground", &foreground); config_lookup_bool(&config, "numeric", &numeric); - config_lookup_bool(&config, "transparent", &g_transparent); + config_lookup_bool(&config, "transparent", &transparent); if (config_lookup_int(&config, "timeout", (int *)&timeout) == CONFIG_TRUE) { probing_timeout = timeout; diff --git a/sslh.pod b/sslh.pod index 8b08d88..b019da8 100644 --- a/sslh.pod +++ b/sslh.pod @@ -6,7 +6,7 @@ =head1 SYNOPSIS -sslh [B<-F>I] [ B<-t> I ] [B<--transparent>] [B<-p> I [B<-p> I ...] [B<--ssl> I] [B<--tls> I] [B<--ssh> I] [B<--openvpn> I] [B<--http> I] [B<--xmpp> I] [B<--tinc> I] [B<--anyprot> I] [B<--on-timeout> I] [B<-u> I] [B<-P> I] [-v] [-i] [-V] [-f] [-n] +sslh [B<-F> I] [ B<-t> I ] [B<--transparent>] [B<-p> I [B<-p> I ...] [B<--ssl> I] [B<--tls> I] [B<--ssh> I] [B<--openvpn> I] [B<--http> I] [B<--xmpp> I] [B<--tinc> I] [B<--anyprot> I] [B<--on-timeout> I] [B<-u> I] [B<-P> I] [-v] [-i] [-V] [-f] [-n] =head1 DESCRIPTION @@ -78,15 +78,12 @@ connections and LOG_ERR for failures. =over 4 -=item B<-F>I, B<--config> I +=item B<-F> I, B<--config> I Uses I as configuration file. If other command-line options are specified, they will override the configuration file's settings. -When using the shorthand version, make sure there should be -no space between B<-F> and the I. - =item B<-t> I, B<--timeout> I Timeout before forwarding the connection to the timeout From e4a4e04bf87cc6460fe9790ffc4a796e60ab698c Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Sun, 8 Jan 2017 13:00:19 +0100 Subject: [PATCH 02/10] Clarify no space after -F (Issue 108, take 2) --- sslh-main.c | 4 ++-- sslh.pod | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sslh-main.c b/sslh-main.c index 3242cc4..37e76d9 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -39,7 +39,7 @@ const char* USAGE_STRING = "sslh " VERSION "\n" \ "usage:\n" \ -"\tsslh [-v] [-i] [-V] [-f] [-n] [--transparent] [-F ]\n" +"\tsslh [-v] [-i] [-V] [-f] [-n] [--transparent] [-F]\n" "\t[-t ] [-P ] -u -p [-p ...] \n" \ "%s\n\n" /* Dynamically built list of builtin protocols */ \ "\t[--on-timeout ]\n" \ @@ -49,7 +49,7 @@ const char* USAGE_STRING = "-n: numeric output\n" \ "-u: specify under which user to run\n" \ "--transparent: behave as a transparent proxy\n" \ -"-F: use configuration file\n" \ +"-F: use configuration file (warning: no space between -F and file name!)\n" \ "--on-timeout: connect to specified address upon timeout (default: ssh address)\n" \ "-t: seconds to wait before connecting to --on-timeout address.\n" \ "-p: address and port to listen on.\n Can be used several times to bind to several addresses.\n" \ diff --git a/sslh.pod b/sslh.pod index b019da8..8b08d88 100644 --- a/sslh.pod +++ b/sslh.pod @@ -6,7 +6,7 @@ =head1 SYNOPSIS -sslh [B<-F> I] [ B<-t> I ] [B<--transparent>] [B<-p> I [B<-p> I ...] [B<--ssl> I] [B<--tls> I] [B<--ssh> I] [B<--openvpn> I] [B<--http> I] [B<--xmpp> I] [B<--tinc> I] [B<--anyprot> I] [B<--on-timeout> I] [B<-u> I] [B<-P> I] [-v] [-i] [-V] [-f] [-n] +sslh [B<-F>I] [ B<-t> I ] [B<--transparent>] [B<-p> I [B<-p> I ...] [B<--ssl> I] [B<--tls> I] [B<--ssh> I] [B<--openvpn> I] [B<--http> I] [B<--xmpp> I] [B<--tinc> I] [B<--anyprot> I] [B<--on-timeout> I] [B<-u> I] [B<-P> I] [-v] [-i] [-V] [-f] [-n] =head1 DESCRIPTION @@ -78,12 +78,15 @@ connections and LOG_ERR for failures. =over 4 -=item B<-F> I, B<--config> I +=item B<-F>I, B<--config> I Uses I as configuration file. If other command-line options are specified, they will override the configuration file's settings. +When using the shorthand version, make sure there should be +no space between B<-F> and the I. + =item B<-t> I, B<--timeout> I Timeout before forwarding the connection to the timeout From 70a2ea926efc8ca455b08d230b90789a57bc29c6 Mon Sep 17 00:00:00 2001 From: "Yann E. MORIN" Date: Thu, 23 Feb 2017 22:49:31 +0100 Subject: [PATCH 03/10] Makefile: fix parallel build version.h is included by some .o files, but it is generated. As such, it must be a dependency of those .o files. Rather than filter exactly which .o file needs it, just add a generic dependency for all .o files on version.h. Signed-off-by: "Yann E. MORIN" --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index b1cf9ce..7ebec92 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,8 @@ version.h: sslh: sslh-fork sslh-select +$(OBJS): version.h + 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 From 078827ad3fedb640e45e079a5d34e2771e04a36f Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Thu, 6 Apr 2017 16:26:27 +0200 Subject: [PATCH 04/10] Some systems define IP_FREEBIND but don't implement it which result in setsockopt() failing. No need to die in that case, just ignore the error. --- common.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common.c b/common.c index 394cdb1..7799b1e 100644 --- a/common.c +++ b/common.c @@ -133,8 +133,12 @@ int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list) if (IP_FREEBIND) { res = setsockopt((*sockfd)[i], IPPROTO_IP, IP_FREEBIND, (char*)&one, sizeof(one)); - check_res_dumpdie(res, addr, "setsockopt(IP_FREEBIND)"); - } + if (res == -1) { + fprintf(stderr, "%s:%s: %s\n", + sprintaddr(buf, sizeof(buf), addr), + syscall, + strerror(errno)); + } res = bind((*sockfd)[i], addr->ai_addr, addr->ai_addrlen); check_res_dumpdie(res, addr, "bind"); From b0f4e24ce016310b8cf7f4995632f5e282fa63ee Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Thu, 6 Apr 2017 17:13:11 +0200 Subject: [PATCH 05/10] IP_FREEBIND: real fix, ignore catastrophic previous checkin --- common.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/common.c b/common.c index 7799b1e..cc85bb1 100644 --- a/common.c +++ b/common.c @@ -48,8 +48,13 @@ struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */ int allow_severity =0, deny_severity = 0; #endif +typedef enum { + CR_DIE, + CR_WARN +} CR_ACTION; + /* check result and die, printing the offending address and error */ -void check_res_dumpdie(int res, struct addrinfo *addr, char* syscall) +void check_res_dump(CR_ACTION act, int res, struct addrinfo *addr, char* syscall) { char buf[NI_MAXHOST]; @@ -58,7 +63,9 @@ void check_res_dumpdie(int res, struct addrinfo *addr, char* syscall) sprintaddr(buf, sizeof(buf), addr), syscall, strerror(errno)); - exit(1); + + if (act == CR_DIE) + exit(1); } } @@ -119,32 +126,28 @@ int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list) saddr = (struct sockaddr_storage*)addr->ai_addr; (*sockfd)[i] = socket(saddr->ss_family, SOCK_STREAM, 0); - check_res_dumpdie((*sockfd)[i], addr, "socket"); + check_res_dump(CR_DIE, (*sockfd)[i], addr, "socket"); one = 1; res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)); - check_res_dumpdie(res, addr, "setsockopt(SO_REUSEADDR)"); + check_res_dump(CR_DIE, res, addr, "setsockopt(SO_REUSEADDR)"); if (addr->ai_flags & SO_KEEPALIVE) { res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(one)); - check_res_dumpdie(res, addr, "setsockopt(SO_KEEPALIVE)"); + check_res_dump(CR_DIE, res, addr, "setsockopt(SO_KEEPALIVE)"); printf("set up keepalive\n"); } if (IP_FREEBIND) { res = setsockopt((*sockfd)[i], IPPROTO_IP, IP_FREEBIND, (char*)&one, sizeof(one)); - if (res == -1) { - fprintf(stderr, "%s:%s: %s\n", - sprintaddr(buf, sizeof(buf), addr), - syscall, - strerror(errno)); + check_res_dump(CR_WARN, res, addr, "setsockopt(IP_FREEBIND)"); } res = bind((*sockfd)[i], addr->ai_addr, addr->ai_addrlen); - check_res_dumpdie(res, addr, "bind"); + check_res_dump(CR_DIE, res, addr, "bind"); res = listen ((*sockfd)[i], 50); - check_res_dumpdie(res, addr, "listen"); + check_res_dump(CR_DIE, res, addr, "listen"); } From cce42c68822f605ff7297c136312af50bfd5fdad Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Tue, 18 Apr 2017 20:53:19 +0200 Subject: [PATCH 06/10] re-indent --- systemd-sslh-generator.c | 195 +++++++++++++++++++-------------------- 1 file changed, 94 insertions(+), 101 deletions(-) diff --git a/systemd-sslh-generator.c b/systemd-sslh-generator.c index 5909a5b..f9280ef 100644 --- a/systemd-sslh-generator.c +++ b/systemd-sslh-generator.c @@ -5,9 +5,8 @@ static char* resolve_listen(const char *hostname, const char *port) { - -/* Need room in the strcat for \0 and : - * the format in the socket unit file is hostname:port */ + /* Need room in the strcat for \0 and : + * the format in the socket unit file is hostname:port */ char *conn = (char*)malloc(strlen(hostname)+strlen(port)+2); strcpy(conn, hostname); strcat(conn, ":"); @@ -19,135 +18,129 @@ static char* resolve_listen(const char *hostname, const char *port) { static int get_listen_from_conf(const char *filename, char **listen) { + config_t config; + config_setting_t *setting, *addr; + const char *hostname, *port; + int len = 0; - config_t config; - config_setting_t *setting, *addr; - const char *hostname, *port; - int len = 0; - -/* look up the listen stanzas in the config file so these - * can be used in the socket file generated */ - - config_init(&config); - if (config_read_file(&config, filename) == CONFIG_FALSE) { - /* we don't care if file is missing, skip it */ - if (config_error_line(&config) != 0) { - fprintf(stderr, "%s:%d:%s\n", - filename, - config_error_line(&config), - config_error_text(&config)); - return -1; - } - } else { - setting = config_lookup(&config, "listen"); - if (setting) { - len = config_setting_length(setting); - for (int 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)); + /* look up the listen stanzas in the config file so these + * can be used in the socket file generated */ + config_init(&config); + if (config_read_file(&config, filename) == CONFIG_FALSE) { + /* we don't care if file is missing, skip it */ + if (config_error_line(&config) != 0) { + fprintf(stderr, "%s:%d:%s\n", + filename, + config_error_line(&config), + config_error_text(&config)); return -1; - } else { - - listen[i] = malloc(strlen(resolve_listen(hostname, port))); - strcpy(listen[i], resolve_listen(hostname, port)); } - } + } else { + setting = config_lookup(&config, "listen"); + if (setting) { + len = config_setting_length(setting); + for (int 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; + } else { + listen[i] = malloc(strlen(resolve_listen(hostname, port))); + strcpy(listen[i], resolve_listen(hostname, port)); + } + } + } } - } - return len; + return len; } static int write_socket_unit(FILE *socket, char **listen, int num_addr, const char *source) { - fprintf(socket, - "# Automatically generated by systemd-sslh-generator\n\n" - "[Unit]\n" - "Before=sslh.service\n" - "SourcePath=%s\n" - "Documentation=man:sslh(8) man:systemd-sslh-generator(8)\n\n" - "[Socket]\n" - "FreeBind=true\n", - source); + fprintf(socket, + "# Automatically generated by systemd-sslh-generator\n\n" + "[Unit]\n" + "Before=sslh.service\n" + "SourcePath=%s\n" + "Documentation=man:sslh(8) man:systemd-sslh-generator(8)\n\n" + "[Socket]\n" + "FreeBind=true\n", + source); - for (int i = 0; i < num_addr; i++) { - fprintf(socket, "ListenStream=%s\n", listen[i]); - } + for (int i = 0; i < num_addr; i++) { + fprintf(socket, "ListenStream=%s\n", listen[i]); + } -return 0; + return 0; } static int gen_sslh_config(char *runtime_unit_dir) { + char *sslh_conf; + int num_addr; + FILE *config; + char **listen; + FILE *runtime_conf_fd = stdout; + const char *unit_file; - char *sslh_conf; - int num_addr; - FILE *config; - char **listen; - FILE *runtime_conf_fd = stdout; - const char *unit_file; + /* There are two default locations so check both with first given preference */ + sslh_conf = "/etc/sslh.cfg"; -/* There are two default locations so check both with first given preference */ - sslh_conf = "/etc/sslh.cfg"; - - config = fopen(sslh_conf, "r"); - if (config == NULL) { - sslh_conf="/etc/sslh/sslh.cfg"; - config = fopen(sslh_conf, "r"); - if (config == NULL) { - return -1; + config = fopen(sslh_conf, "r"); + if (config == NULL) { + sslh_conf="/etc/sslh/sslh.cfg"; + config = fopen(sslh_conf, "r"); + if (config == NULL) { + return -1; + } } - } - fclose(config); + fclose(config); - num_addr = get_listen_from_conf(sslh_conf, listen); - if (num_addr < 0) - return -1; + num_addr = get_listen_from_conf(sslh_conf, listen); + if (num_addr < 0) + return -1; -/* If this is run by systemd directly write to the location told to - * otherwise write to standard out so that it's trivial to check what - * will be written */ - if (runtime_unit_dir != "") { - unit_file = "/sslh.socket"; - size_t uf_len = strlen(unit_file); - size_t runtime_len = strlen(runtime_unit_dir) + uf_len + 1; - char *runtime_conf = malloc(runtime_len); - strcpy(runtime_conf, runtime_unit_dir); - strcat(runtime_conf, unit_file); - runtime_conf_fd = fopen(runtime_conf, "w"); - } + /* If this is run by systemd directly write to the location told to + * otherwise write to standard out so that it's trivial to check what + * will be written */ + if (runtime_unit_dir != "") { + unit_file = "/sslh.socket"; + size_t uf_len = strlen(unit_file); + size_t runtime_len = strlen(runtime_unit_dir) + uf_len + 1; + char *runtime_conf = malloc(runtime_len); + strcpy(runtime_conf, runtime_unit_dir); + strcat(runtime_conf, unit_file); + runtime_conf_fd = fopen(runtime_conf, "w"); + } - return write_socket_unit(runtime_conf_fd, listen, num_addr, sslh_conf); - + return write_socket_unit(runtime_conf_fd, listen, num_addr, sslh_conf); } + int main(int argc, char *argv[]){ + int r = 0; + int k; + char *runtime_unit_dest = ""; - int r = 0; - int k; - char *runtime_unit_dest = ""; + if (argc > 1 && (argc != 4) ) { + printf("This program takes three or no arguments.\n"); + return -1; + } - if (argc > 1 && (argc != 4) ) { - printf("This program takes three or no arguments.\n"); - return -1; - } + if (argc > 1) + runtime_unit_dest = argv[1]; - if (argc > 1) - runtime_unit_dest = argv[1]; - - k = gen_sslh_config(runtime_unit_dest); - if (k < 0) - r = k; - - return r < 0 ? -1 : 0; + k = gen_sslh_config(runtime_unit_dest); + if (k < 0) + r = k; + return r < 0 ? -1 : 0; } From 7d561af4235ffc6c0203fc66d4998c74384c7fa8 Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Tue, 18 Apr 2017 21:04:30 +0200 Subject: [PATCH 07/10] allocate listen[] before writing to it... --- systemd-sslh-generator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/systemd-sslh-generator.c b/systemd-sslh-generator.c index f9280ef..537d845 100644 --- a/systemd-sslh-generator.c +++ b/systemd-sslh-generator.c @@ -17,7 +17,7 @@ static char* resolve_listen(const char *hostname, const char *port) { } -static int get_listen_from_conf(const char *filename, char **listen) { +static int get_listen_from_conf(const char *filename, char **listen[]) { config_t config; config_setting_t *setting, *addr; const char *hostname, *port; @@ -39,6 +39,7 @@ static int get_listen_from_conf(const char *filename, char **listen) { setting = config_lookup(&config, "listen"); if (setting) { len = config_setting_length(setting); + *listen = malloc(len * sizeof(**listen)); for (int i = 0; i < len; i++) { addr = config_setting_get_elem(setting, i); if (! (config_setting_lookup_string(addr, "host", &hostname) && @@ -48,8 +49,8 @@ static int get_listen_from_conf(const char *filename, char **listen) { config_setting_source_line(addr)); return -1; } else { - listen[i] = malloc(strlen(resolve_listen(hostname, port))); - strcpy(listen[i], resolve_listen(hostname, port)); + (*listen)[i] = malloc(strlen(resolve_listen(hostname, port))); + strcpy((*listen)[i], resolve_listen(hostname, port)); } } } @@ -59,7 +60,7 @@ static int get_listen_from_conf(const char *filename, char **listen) { } -static int write_socket_unit(FILE *socket, char **listen, int num_addr, const char *source) { +static int write_socket_unit(FILE *socket, char *listen[], int num_addr, const char *source) { fprintf(socket, "# Automatically generated by systemd-sslh-generator\n\n" @@ -100,8 +101,7 @@ static int gen_sslh_config(char *runtime_unit_dir) { fclose(config); - - num_addr = get_listen_from_conf(sslh_conf, listen); + num_addr = get_listen_from_conf(sslh_conf, &listen); if (num_addr < 0) return -1; From 00d5872aa176a23588f143551aa4b7e8dd1c0ca6 Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Fri, 21 Apr 2017 22:33:02 +0200 Subject: [PATCH 08/10] ignore brackets in hostname in config files --- common.c | 30 +++++++++++++++++------------- common.h | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/common.c b/common.c index cc85bb1..810a610 100644 --- a/common.c +++ b/common.c @@ -442,16 +442,31 @@ 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 + * + * *host gets modified **/ -int resolve_split_name(struct addrinfo **out, const char* host, const char* serv) +int resolve_split_name(struct addrinfo **out, char* host, const char* serv) { struct addrinfo hint; + char *end; int res; memset(&hint, 0, sizeof(hint)); hint.ai_family = PF_UNSPEC; hint.ai_socktype = SOCK_STREAM; + /* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets + * around IP address */ + if (host[0] == '[') { + end = strrchr(host, ']'); + if (!end) { + fprintf(stderr, "%s: no closing bracket in IPv6 address?\n", host); + } + host++; /* skip first bracket */ + *end = 0; /* remove last bracket */ + } + + res = getaddrinfo(host, serv, &hint, out); if (res) log_message(LOG_ERR, "%s `%s:%s'\n", gai_strerror(res), host, serv); @@ -464,7 +479,7 @@ fullname: input string -- it gets clobbered */ void resolve_name(struct addrinfo **out, char* fullname) { - char *serv, *host, *end; + char *serv, *host; int res; /* Find port */ @@ -478,17 +493,6 @@ void resolve_name(struct addrinfo **out, char* fullname) host = fullname; - /* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets - * around IP address */ - if (host[0] == '[') { - end = strrchr(host, ']'); - if (!end) { - fprintf(stderr, "%s: no closing bracket in IPv6 address?\n", host); - } - host++; /* skip first bracket */ - *end = 0; /* remove last bracket */ - } - res = resolve_split_name(out, host, serv); if (res) { fprintf(stderr, "%s `%s'\n", gai_strerror(res), fullname); diff --git a/common.h b/common.h index 701b337..c83eb91 100644 --- a/common.h +++ b/common.h @@ -106,7 +106,7 @@ void drop_privileges(const char* user_name); 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, const char* port); int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list); From 6cc33820d166bc790c79f8e42aec8f53bcefd2ba Mon Sep 17 00:00:00 2001 From: Jonathan McCrohan Date: Tue, 6 Jun 2017 01:11:29 +0100 Subject: [PATCH 09/10] tls: permit wildcard ALPN/SNI values Use fnmatch(3) to provide support for glob style wildcard values in the ALPN and SNI parameters of the TLS probe. Signed-off-by: Jonathan McCrohan --- tls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tls.c b/tls.c index 8640dec..fc4ae38 100644 --- a/tls.c +++ b/tls.c @@ -30,6 +30,7 @@ */ #include #include /* malloc() */ +#include /* fnmatch() */ #include "tls.h" #define TLS_HEADER_LEN 5 @@ -290,7 +291,7 @@ has_match(char** list, const char* name, size_t name_len) { for (item = list; *item; item++) { if (verbose) fprintf(stderr, "matching [%.*s] with [%s]\n", (int)name_len, name, *item); - if(!strncmp(*item, name, name_len)) { + if(!fnmatch(*item, name, 0)) { return 1; } } From 1e65088b7e6388694b36126cc59c6625b53f4fe6 Mon Sep 17 00:00:00 2001 From: Jonathan McCrohan Date: Tue, 6 Jun 2017 01:37:07 +0100 Subject: [PATCH 10/10] example.cfg: Add Let's Encrypt support to config Provides a sample config for Let's Encrypt using the tls-sni-* challenges. Requires wildcard support added in 6cc3382. Signed-off-by: Jonathan McCrohan --- example.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example.cfg b/example.cfg index 371bcf0..b5cb37a 100644 --- a/example.cfg +++ b/example.cfg @@ -74,6 +74,9 @@ protocols: { name: "regex"; host: "localhost"; port: "1194"; regex_patterns: [ "^\x00[\x0D-\xFF]$", "^\x00[\x0D-\xFF]\x38" ]; }, # Jabber { name: "regex"; host: "localhost"; port: "5222"; regex_patterns: [ "jabber" ]; }, + +# Let's Encrypt (tls-sni-* challenges) + { name: "tls"; host: "localhost"; port: "letsencrypt-client"; sni_hostnames: [ "*.*.acme.invalid" ]; log_level: 0;}, # Catch-all { name: "regex"; host: "localhost"; port: "443"; regex_patterns: [ "" ]; },