git ssb

0+

cel / sslh



Commit 21f524f71165538dcde9f8de32b9f69385ba0c87

Add support for wildcard ALPN/SNI values

Yves Rutschlé committed on 6/12/2017, 9:05:12 PM
Parent: 718fe0e2e9f339a022d9bc13285017fdd76a32e1
Parent: 1e65088b7e6388694b36126cc59c6625b53f4fe6

Files changed

Makefilechanged
common.cchanged
common.hchanged
example.cfgchanged
probe.cchanged
probe.hchanged
sslh-main.cchanged
systemd-sslh-generator.cchanged
tls.cchanged
MakefileView
@@ -66,8 +66,10 @@
6666 ./genver.sh >version.h
6767
6868 sslh: sslh-fork sslh-select
6969
70+$(OBJS): version.h
71+
7072 sslh-fork: version.h $(OBJS) sslh-fork.o Makefile common.h
7173 $(CC) $(CFLAGS) $(LDFLAGS) -o sslh-fork sslh-fork.o $(OBJS) $(LIBS)
7274 #strip sslh-fork
7375
common.cView
@@ -36,8 +36,9 @@
3636 int probing_timeout = 2;
3737 int inetd = 0;
3838 int foreground = 0;
3939 int background = 0;
40+int transparent = 0;
4041 int numeric = 0;
4142 const char *user_name, *pid_file;
4243
4344 struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */
@@ -46,19 +47,26 @@
4647 #include <tcpd.h>
4748 int allow_severity =0, deny_severity = 0;
4849 #endif
4950
51+typedef enum {
52+ CR_DIE,
53+ CR_WARN
54+} CR_ACTION;
55+
5056 /* check result and die, printing the offending address and error */
51-void check_res_dumpdie(int res, struct addrinfo *addr, char* syscall)
57+void check_res_dump(CR_ACTION act, int res, struct addrinfo *addr, char* syscall)
5258 {
5359 char buf[NI_MAXHOST];
5460
5561 if (res == -1) {
5662 fprintf(stderr, "%s:%s: %s\n",
5763 sprintaddr(buf, sizeof(buf), addr),
5864 syscall,
5965 strerror(errno));
60- exit(1);
66+
67+ if (act == CR_DIE)
68+ exit(1);
6169 }
6270 }
6371
6472 int get_fd_sockets(int *sockfd[])
@@ -117,30 +125,30 @@
117125 }
118126 saddr = (struct sockaddr_storage*)addr->ai_addr;
119127
120128 (*sockfd)[i] = socket(saddr->ss_family, SOCK_STREAM, 0);
121- check_res_dumpdie((*sockfd)[i], addr, "socket");
129+ check_res_dump(CR_DIE, (*sockfd)[i], addr, "socket");
122130
123131 one = 1;
124132 res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one));
125- check_res_dumpdie(res, addr, "setsockopt(SO_REUSEADDR)");
133+ check_res_dump(CR_DIE, res, addr, "setsockopt(SO_REUSEADDR)");
126134
127135 if (addr->ai_flags & SO_KEEPALIVE) {
128136 res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(one));
129- check_res_dumpdie(res, addr, "setsockopt(SO_KEEPALIVE)");
137+ check_res_dump(CR_DIE, res, addr, "setsockopt(SO_KEEPALIVE)");
130138 printf("set up keepalive\n");
131139 }
132140
133141 if (IP_FREEBIND) {
134142 res = setsockopt((*sockfd)[i], IPPROTO_IP, IP_FREEBIND, (char*)&one, sizeof(one));
135- check_res_dumpdie(res, addr, "setsockopt(IP_FREEBIND)");
136- }
143+ check_res_dump(CR_WARN, res, addr, "setsockopt(IP_FREEBIND)");
144+ }
137145
138146 res = bind((*sockfd)[i], addr->ai_addr, addr->ai_addrlen);
139- check_res_dumpdie(res, addr, "bind");
147+ check_res_dump(CR_DIE, res, addr, "bind");
140148
141149 res = listen ((*sockfd)[i], 50);
142- check_res_dumpdie(res, addr, "listen");
150+ check_res_dump(CR_DIE, res, addr, "listen");
143151
144152 }
145153
146154 return num_addr;
@@ -235,9 +243,9 @@
235243 CHECK_RES_RETURN(res, "getpeername");
236244
237245 for (a = cnx->proto->saddr; a; a = a->ai_next) {
238246 /* When transparent, make sure both connections use the same address family */
239- if (cnx->proto->transparent && a->ai_family != from.ai_addr->sa_family)
247+ if (transparent && a->ai_family != from.ai_addr->sa_family)
240248 continue;
241249 if (verbose)
242250 fprintf(stderr, "connecting to %s family %d len %d\n",
243251 sprintaddr(buf, sizeof(buf), a),
@@ -248,9 +256,9 @@
248256 if (fd == -1) {
249257 log_message(LOG_ERR, "forward to %s failed:socket: %s\n",
250258 cnx->proto->description, strerror(errno));
251259 } else {
252- if (cnx->proto->transparent) {
260+ if (transparent) {
253261 res = bind_peer(fd, fd_from);
254262 CHECK_RES_RETURN(res, "bind_peer");
255263 }
256264 res = connect(fd, a->ai_addr, a->ai_addrlen);
@@ -433,18 +441,33 @@
433441 }
434442
435443 /* Turns a hostname and port (or service) into a list of struct addrinfo
436444 * returns 0 on success, -1 otherwise and logs error
445+ *
446+ * *host gets modified
437447 **/
438-int resolve_split_name(struct addrinfo **out, const char* host, const char* serv)
448+int resolve_split_name(struct addrinfo **out, char* host, const char* serv)
439449 {
440450 struct addrinfo hint;
451+ char *end;
441452 int res;
442453
443454 memset(&hint, 0, sizeof(hint));
444455 hint.ai_family = PF_UNSPEC;
445456 hint.ai_socktype = SOCK_STREAM;
446457
458+ /* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets
459+ * around IP address */
460+ if (host[0] == '[') {
461+ end = strrchr(host, ']');
462+ if (!end) {
463+ fprintf(stderr, "%s: no closing bracket in IPv6 address?\n", host);
464+ }
465+ host++; /* skip first bracket */
466+ *end = 0; /* remove last bracket */
467+ }
468+
469+
447470 res = getaddrinfo(host, serv, &hint, out);
448471 if (res)
449472 log_message(LOG_ERR, "%s `%s:%s'\n", gai_strerror(res), host, serv);
450473 return res;
@@ -455,9 +478,9 @@
455478 fullname: input string -- it gets clobbered
456479 */
457480 void resolve_name(struct addrinfo **out, char* fullname)
458481 {
459- char *serv, *host, *end;
482+ char *serv, *host;
460483 int res;
461484
462485 /* Find port */
463486 char *sep = strrchr(fullname, ':');
@@ -469,19 +492,8 @@
469492 *sep = 0;
470493
471494 host = fullname;
472495
473- /* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets
474- * around IP address */
475- if (host[0] == '[') {
476- end = strrchr(host, ']');
477- if (!end) {
478- fprintf(stderr, "%s: no closing bracket in IPv6 address?\n", host);
479- }
480- host++; /* skip first bracket */
481- *end = 0; /* remove last bracket */
482- }
483-
484496 res = resolve_split_name(out, host, serv);
485497 if (res) {
486498 fprintf(stderr, "%s `%s'\n", gai_strerror(res), fullname);
487499 if (res == EAI_SERVICE)
common.hView
@@ -105,16 +105,17 @@
105105 void drop_privileges(const char* user_name);
106106 void write_pid_file(const char* pidfile);
107107 void log_message(int type, char* msg, ...);
108108 void dump_connection(struct connection *cnx);
109-int resolve_split_name(struct addrinfo **out, const char* hostname, const char* port);
109+int resolve_split_name(struct addrinfo **out, char* hostname, const char* port);
110110
111111 int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list);
112112
113113 int defer_write(struct queue *q, void* data, int data_size);
114114 int flush_deferred(struct queue *q);
115115
116-extern int probing_timeout, verbose, inetd, foreground, background, numeric;
116+extern int probing_timeout, verbose, inetd, foreground,
117+ background, transparent, numeric;
117118 extern struct sockaddr_storage addr_ssl, addr_ssh, addr_openvpn;
118119 extern struct addrinfo *addr_listen;
119120 extern const char* USAGE_STRING;
120121 extern const char* user_name, *pid_file;
example.cfgView
@@ -73,8 +73,11 @@
7373 # OpenVPN
7474 { name: "regex"; host: "localhost"; port: "1194"; regex_patterns: [ "^\x00[\x0D-\xFF]$", "^\x00[\x0D-\xFF]\x38" ]; },
7575 # Jabber
7676 { name: "regex"; host: "localhost"; port: "5222"; regex_patterns: [ "jabber" ]; },
77+
78+# Let's Encrypt (tls-sni-* challenges)
79+ { name: "tls"; host: "localhost"; port: "letsencrypt-client"; sni_hostnames: [ "*.*.acme.invalid" ]; log_level: 0;},
7780
7881 # Catch-all
7982 { name: "regex"; host: "localhost"; port: "443"; regex_patterns: [ "" ]; },
8083
probe.cView
@@ -44,18 +44,18 @@
4444
4545 /* Table of protocols that have a built-in probe
4646 */
4747 static struct proto builtins[] = {
48- /* description service saddr log_level keepalive transparent probe */
49- { "ssh", "sshd", NULL, 1, 0, 0, is_ssh_protocol},
50- { "openvpn", NULL, NULL, 1, 0, 0, is_openvpn_protocol },
51- { "tinc", NULL, NULL, 1, 0, 0, is_tinc_protocol },
52- { "xmpp", NULL, NULL, 1, 0, 0, is_xmpp_protocol },
53- { "http", NULL, NULL, 1, 0, 0, is_http_protocol },
54- { "ssl", NULL, NULL, 1, 0, 0, is_tls_protocol },
55- { "tls", NULL, NULL, 1, 0, 0, is_tls_protocol },
56- { "adb", NULL, NULL, 1, 0, 0, is_adb_protocol },
57- { "anyprot", NULL, NULL, 1, 0, 0, is_true }
48+ /* description service saddr log_level keepalive probe */
49+ { "ssh", "sshd", NULL, 1, 0, is_ssh_protocol},
50+ { "openvpn", NULL, NULL, 1, 0, is_openvpn_protocol },
51+ { "tinc", NULL, NULL, 1, 0, is_tinc_protocol },
52+ { "xmpp", NULL, NULL, 1, 0, is_xmpp_protocol },
53+ { "http", NULL, NULL, 1, 0, is_http_protocol },
54+ { "ssl", NULL, NULL, 1, 0, is_tls_protocol },
55+ { "tls", NULL, NULL, 1, 0, is_tls_protocol },
56+ { "adb", NULL, NULL, 1, 0, is_adb_protocol },
57+ { "anyprot", NULL, NULL, 1, 0, is_true }
5858 };
5959
6060 static struct proto *protocols;
6161 static char* on_timeout = "ssh";
probe.hView
@@ -23,9 +23,8 @@
2323 int log_level; /* 0: No logging of connection
2424 * 1: Log incoming connection
2525 */
2626 int keepalive; /* 0: No keepalive ; 1: Set Keepalive for this connection */
27- int transparent; /* 0: opaque proxy ; 1: transparent proxy */
2827
2928 /* function to probe that protocol; parameters are buffer and length
3029 * containing the data to probe, and a pointer to the protocol structure */
3130 T_PROBE* probe;
sslh-main.cView
@@ -60,16 +60,13 @@
6060
6161 /* Constants for options that have no one-character shorthand */
6262 #define OPT_ONTIMEOUT 257
6363
64-/* Global setting for transparent proxying */
65-int g_transparent = 0;
66-
6764 static struct option const_options[] = {
6865 { "inetd", no_argument, &inetd, 1 },
6966 { "foreground", no_argument, &foreground, 1 },
7067 { "background", no_argument, &background, 1 },
71- { "transparent", no_argument, &g_transparent, 1 },
68+ { "transparent", no_argument, &transparent, 1 },
7269 { "numeric", no_argument, &numeric, 1 },
7370 { "verbose", no_argument, &verbose, 1 },
7471 { "user", required_argument, 0, 'u' },
7572 { "config", optional_argument, 0, 'F' },
@@ -125,18 +122,16 @@
125122 struct proto *p;
126123
127124 for (p = get_first_protocol(); p; p = p->next) {
128125 fprintf(stderr,
129- "%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s%s]\n",
126+ "%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s]\n",
130127 p->description,
131128 sprintaddr(buf, sizeof(buf), p->saddr),
132129 p->service,
133130 p->log_level,
134131 p->saddr->ai_family,
135132 p->saddr->ai_addr->sa_family,
136- p->keepalive ? "keepalive " : "",
137- p->transparent ? "transparent" : ""
138- );
133+ p->keepalive ? "keepalive" : "");
139134 }
140135 fprintf(stderr, "listening on:\n");
141136 for (a = addr_listen; a; a = a->ai_next) {
142137 fprintf(stderr,
@@ -311,9 +306,8 @@
311306 )) {
312307 p->description = name;
313308 config_setting_lookup_string(prot, "service", &(p->service));
314309 config_setting_lookup_bool(prot, "keepalive", &p->keepalive);
315- config_setting_lookup_bool(prot, "transparent", &p->transparent);
316310
317311 if (config_setting_lookup_int(prot, "log_level", &p->log_level) == CONFIG_FALSE) {
318312 p->log_level = 1;
319313 }
@@ -381,9 +375,9 @@
381375 config_lookup_bool(&config, "verbose", &verbose);
382376 config_lookup_bool(&config, "inetd", &inetd);
383377 config_lookup_bool(&config, "foreground", &foreground);
384378 config_lookup_bool(&config, "numeric", &numeric);
385- config_lookup_bool(&config, "transparent", &g_transparent);
379+ config_lookup_bool(&config, "transparent", &transparent);
386380
387381 if (config_lookup_int(&config, "timeout", (int *)&timeout) == CONFIG_TRUE) {
388382 probing_timeout = timeout;
389383 }
systemd-sslh-generator.cView
@@ -4,11 +4,10 @@
44 #include <stdlib.h>
55
66
77 static char* resolve_listen(const char *hostname, const char *port) {
8-
9-/* Need room in the strcat for \0 and :
10- * the format in the socket unit file is hostname:port */
8+ /* Need room in the strcat for \0 and :
9+ * the format in the socket unit file is hostname:port */
1110 char *conn = (char*)malloc(strlen(hostname)+strlen(port)+2);
1211 strcpy(conn, hostname);
1312 strcat(conn, ":");
1413 strcat(conn, port);
@@ -17,137 +16,131 @@
1716
1817 }
1918
2019
21-static int get_listen_from_conf(const char *filename, char **listen) {
20+static int get_listen_from_conf(const char *filename, char **listen[]) {
21+ config_t config;
22+ config_setting_t *setting, *addr;
23+ const char *hostname, *port;
24+ int len = 0;
2225
23- config_t config;
24- config_setting_t *setting, *addr;
25- const char *hostname, *port;
26- int len = 0;
27-
28-/* look up the listen stanzas in the config file so these
29- * can be used in the socket file generated */
30-
31- config_init(&config);
32- if (config_read_file(&config, filename) == CONFIG_FALSE) {
33- /* we don't care if file is missing, skip it */
34- if (config_error_line(&config) != 0) {
35- fprintf(stderr, "%s:%d:%s\n",
36- filename,
37- config_error_line(&config),
38- config_error_text(&config));
39- return -1;
40- }
41- } else {
42- setting = config_lookup(&config, "listen");
43- if (setting) {
44- len = config_setting_length(setting);
45- for (int i = 0; i < len; i++) {
46- addr = config_setting_get_elem(setting, i);
47- if (! (config_setting_lookup_string(addr, "host", &hostname) &&
48- config_setting_lookup_string(addr, "port", &port))) {
49- fprintf(stderr,
50- "line %d:Incomplete specification (hostname and port required)\n",
51- config_setting_source_line(addr));
26+ /* look up the listen stanzas in the config file so these
27+ * can be used in the socket file generated */
28+ config_init(&config);
29+ if (config_read_file(&config, filename) == CONFIG_FALSE) {
30+ /* we don't care if file is missing, skip it */
31+ if (config_error_line(&config) != 0) {
32+ fprintf(stderr, "%s:%d:%s\n",
33+ filename,
34+ config_error_line(&config),
35+ config_error_text(&config));
5236 return -1;
53- } else {
54-
55- listen[i] = malloc(strlen(resolve_listen(hostname, port)));
56- strcpy(listen[i], resolve_listen(hostname, port));
5737 }
58- }
38+ } else {
39+ setting = config_lookup(&config, "listen");
40+ if (setting) {
41+ len = config_setting_length(setting);
42+ *listen = malloc(len * sizeof(**listen));
43+ for (int i = 0; i < len; i++) {
44+ addr = config_setting_get_elem(setting, i);
45+ if (! (config_setting_lookup_string(addr, "host", &hostname) &&
46+ config_setting_lookup_string(addr, "port", &port))) {
47+ fprintf(stderr,
48+ "line %d:Incomplete specification (hostname and port required)\n",
49+ config_setting_source_line(addr));
50+ return -1;
51+ } else {
52+ (*listen)[i] = malloc(strlen(resolve_listen(hostname, port)));
53+ strcpy((*listen)[i], resolve_listen(hostname, port));
54+ }
55+ }
56+ }
5957 }
60- }
6158
62- return len;
59+ return len;
6360
6461 }
6562
66-static int write_socket_unit(FILE *socket, char **listen, int num_addr, const char *source) {
63+static int write_socket_unit(FILE *socket, char *listen[], int num_addr, const char *source) {
6764
68- fprintf(socket,
69- "# Automatically generated by systemd-sslh-generator\n\n"
70- "[Unit]\n"
71- "Before=sslh.service\n"
72- "SourcePath=%s\n"
73- "Documentation=man:sslh(8) man:systemd-sslh-generator(8)\n\n"
74- "[Socket]\n"
75- "FreeBind=true\n",
76- source);
65+ fprintf(socket,
66+ "# Automatically generated by systemd-sslh-generator\n\n"
67+ "[Unit]\n"
68+ "Before=sslh.service\n"
69+ "SourcePath=%s\n"
70+ "Documentation=man:sslh(8) man:systemd-sslh-generator(8)\n\n"
71+ "[Socket]\n"
72+ "FreeBind=true\n",
73+ source);
7774
78- for (int i = 0; i < num_addr; i++) {
79- fprintf(socket, "ListenStream=%s\n", listen[i]);
80- }
75+ for (int i = 0; i < num_addr; i++) {
76+ fprintf(socket, "ListenStream=%s\n", listen[i]);
77+ }
8178
82-return 0;
79+ return 0;
8380 }
8481
8582 static int gen_sslh_config(char *runtime_unit_dir) {
83+ char *sslh_conf;
84+ int num_addr;
85+ FILE *config;
86+ char **listen;
87+ FILE *runtime_conf_fd = stdout;
88+ const char *unit_file;
8689
87- char *sslh_conf;
88- int num_addr;
89- FILE *config;
90- char **listen;
91- FILE *runtime_conf_fd = stdout;
92- const char *unit_file;
90+ /* There are two default locations so check both with first given preference */
91+ sslh_conf = "/etc/sslh.cfg";
9392
94-/* There are two default locations so check both with first given preference */
95- sslh_conf = "/etc/sslh.cfg";
96-
97- config = fopen(sslh_conf, "r");
98- if (config == NULL) {
99- sslh_conf="/etc/sslh/sslh.cfg";
100- config = fopen(sslh_conf, "r");
101- if (config == NULL) {
102- return -1;
93+ config = fopen(sslh_conf, "r");
94+ if (config == NULL) {
95+ sslh_conf="/etc/sslh/sslh.cfg";
96+ config = fopen(sslh_conf, "r");
97+ if (config == NULL) {
98+ return -1;
99+ }
103100 }
104- }
105101
106- fclose(config);
102+ fclose(config);
107103
104+ num_addr = get_listen_from_conf(sslh_conf, &listen);
105+ if (num_addr < 0)
106+ return -1;
108107
109- num_addr = get_listen_from_conf(sslh_conf, listen);
110- if (num_addr < 0)
111- return -1;
108+ /* If this is run by systemd directly write to the location told to
109+ * otherwise write to standard out so that it's trivial to check what
110+ * will be written */
111+ if (runtime_unit_dir != "") {
112+ unit_file = "/sslh.socket";
113+ size_t uf_len = strlen(unit_file);
114+ size_t runtime_len = strlen(runtime_unit_dir) + uf_len + 1;
115+ char *runtime_conf = malloc(runtime_len);
116+ strcpy(runtime_conf, runtime_unit_dir);
117+ strcat(runtime_conf, unit_file);
118+ runtime_conf_fd = fopen(runtime_conf, "w");
119+ }
112120
113-/* If this is run by systemd directly write to the location told to
114- * otherwise write to standard out so that it's trivial to check what
115- * will be written */
116- if (runtime_unit_dir != "") {
117- unit_file = "/sslh.socket";
118- size_t uf_len = strlen(unit_file);
119- size_t runtime_len = strlen(runtime_unit_dir) + uf_len + 1;
120- char *runtime_conf = malloc(runtime_len);
121- strcpy(runtime_conf, runtime_unit_dir);
122- strcat(runtime_conf, unit_file);
123- runtime_conf_fd = fopen(runtime_conf, "w");
124- }
125121
122+ return write_socket_unit(runtime_conf_fd, listen, num_addr, sslh_conf);
123+}
126124
127- return write_socket_unit(runtime_conf_fd, listen, num_addr, sslh_conf);
128125
129-}
130-
131126 int main(int argc, char *argv[]){
127+ int r = 0;
128+ int k;
129+ char *runtime_unit_dest = "";
132130
133- int r = 0;
134- int k;
135- char *runtime_unit_dest = "";
131+ if (argc > 1 && (argc != 4) ) {
132+ printf("This program takes three or no arguments.\n");
133+ return -1;
134+ }
136135
137- if (argc > 1 && (argc != 4) ) {
138- printf("This program takes three or no arguments.\n");
139- return -1;
140- }
136+ if (argc > 1)
137+ runtime_unit_dest = argv[1];
141138
142- if (argc > 1)
143- runtime_unit_dest = argv[1];
139+ k = gen_sslh_config(runtime_unit_dest);
140+ if (k < 0)
141+ r = k;
144142
145- k = gen_sslh_config(runtime_unit_dest);
146- if (k < 0)
147- r = k;
148-
149- return r < 0 ? -1 : 0;
150-
143+ return r < 0 ? -1 : 0;
151144 }
152145
153146
tls.cView
@@ -29,8 +29,9 @@
2929 * TLS handshake and RFC4366.
3030 */
3131 #include <stdio.h>
3232 #include <stdlib.h> /* malloc() */
33+#include <fnmatch.h> /* fnmatch() */
3334 #include "tls.h"
3435
3536 #define TLS_HEADER_LEN 5
3637 #define TLS_HANDSHAKE_CONTENT_TYPE 0x16
@@ -289,9 +290,9 @@
289290 char **item;
290291
291292 for (item = list; *item; item++) {
292293 if (verbose) fprintf(stderr, "matching [%.*s] with [%s]\n", (int)name_len, name, *item);
293- if(!strncmp(*item, name, name_len)) {
294+ if(!fnmatch(*item, name, 0)) {
294295 return 1;
295296 }
296297 }
297298 return 0;

Built with git-ssb-web