Commit 26b4bcd089f6c3a3c43d1380969c939e600b3ef2
v1.11: 21APR2012
WARNING: defaults have been removed for --user and --pidfile options, update your start-up scripts! No longer stop sslh when reverse DNS requests fail for logging. Added HTTP probe. No longer create new session if running in foreground. No longer default to changing user to 'nobody'. If --user isn't specified, just run as current user. No longer create PID file by default, it should be explicitely set with --pidfile. No longer log to syslog if in foreground. Logs are instead output to stderr. The four changes above make it straightforward to integrate sslh with systemd, and should help with launchd.Yves Rutschle committed on 7/10/2013, 9:14:48 PM
Parent: ae008179f033c8409c69b13787a539351bace626
Files changed
ChangeLog | changed |
Makefile | changed |
README | changed |
common.c | changed |
scripts/etc.default.sslh | changed |
scripts/etc.init.d.sslh | changed |
scripts/etc.rc.d.init.d.sslh.centos | changed |
sslh-fork.c | changed |
sslh-main.c | changed |
sslh.pod | changed |
ChangeLog | ||
---|---|---|
@@ -1,5 +1,30 @@ | ||
1 | -v1.10: | |
1 | +v1.11: 21APR2012 | |
2 | + WARNING: defaults have been removed for --user and | |
3 | + --pidfile options, update your start-up scripts! | |
4 | + | |
5 | + No longer stop sslh when reverse DNS requests fail | |
6 | + for logging. | |
7 | + | |
8 | + Added HTTP probe. | |
9 | + | |
10 | + No longer create new session if running in | |
11 | + foreground. | |
12 | + | |
13 | + No longer default to changing user to 'nobody'. If | |
14 | + --user isn't specified, just run as current user. | |
15 | + | |
16 | + No longer create PID file by default, it should be | |
17 | + explicitely set with --pidfile. | |
18 | + | |
19 | + No longer log to syslog if in foreground. Logs are | |
20 | + instead output to stderr. | |
21 | + | |
22 | + The four changes above make it straightforward to | |
23 | + integrate sslh with systemd, and should help with | |
24 | + launchd. | |
25 | + | |
26 | +v1.10: 27NOV2011 | |
2 | 27 | Fixed calls referring to sockaddr length so they work |
3 | 28 | with FreeBSD. |
4 | 29 | |
5 | 30 | Try target addresses in turn until one works if |
Makefile | ||
---|---|---|
@@ -1,7 +1,7 @@ | ||
1 | 1 | # Configuration |
2 | 2 | |
3 | -VERSION="v1.10" | |
3 | +VERSION="v1.11" | |
4 | 4 | USELIBWRAP= # Use libwrap? |
5 | 5 | COV_TEST= # Perform test coverage? |
6 | 6 | PREFIX=/usr/local |
7 | 7 |
README | ||
---|---|---|
@@ -1,11 +1,11 @@ | ||
1 | 1 | ===== sslh -- A ssl/ssh multiplexer. ===== |
2 | 2 | |
3 | -sslh accepts HTTPS, SSH, OpenVPN, tinc and XMPP connections | |
4 | -on the same port. This makes it possible to connect to any | |
5 | -of these servers on port 443 (e.g. from inside a corporate | |
6 | -firewall, which almost never block port 443) while still | |
7 | -serving HTTPS on that port. | |
3 | +sslh accepts HTTP, HTTPS, SSH, OpenVPN, tinc and XMPP | |
4 | +connections on the same port. This makes it possible to | |
5 | +connect to any of these servers on port 443 (e.g. from | |
6 | +inside a corporate firewall, which almost never block port | |
7 | +443) while still serving HTTPS on that port. | |
8 | 8 | |
9 | 9 | ==== Compile and install ==== |
10 | 10 | |
11 | 11 | If you're lucky, the Makefile will work for you: |
common.c | ||
---|---|---|
@@ -34,8 +34,9 @@ | ||
34 | 34 | int is_ssh_protocol(const char *p, int len); |
35 | 35 | int is_openvpn_protocol(const char *p, int len); |
36 | 36 | int is_tinc_protocol(const char *p, int len); |
37 | 37 | int is_xmpp_protocol(const char *p, int len); |
38 | +int is_http_protocol(const char *p, int len); | |
38 | 39 | int is_true(const char *p, int len) { return 1; } |
39 | 40 | |
40 | 41 | /* Table of all the protocols we know how to connect to. |
41 | 42 | * |
@@ -50,8 +51,9 @@ | ||
50 | 51 | { 0, "ssh", "sshd", {0}, is_ssh_protocol }, |
51 | 52 | { 0, "openvpn", NULL, {0}, is_openvpn_protocol }, |
52 | 53 | { 0, "tinc", NULL, {0}, is_tinc_protocol }, |
53 | 54 | { 0, "xmpp", NULL, {0}, is_xmpp_protocol }, |
55 | + { 0, "http", NULL, {0}, is_http_protocol }, | |
54 | 56 | /* probe for SSL always successes: it's the default, and must be tried last |
55 | 57 | **/ |
56 | 58 | { 0, "ssl", NULL, {0}, is_true } |
57 | 59 | }; |
@@ -337,9 +339,35 @@ | ||
337 | 339 | { |
338 | 340 | return strstr(p, "jabber") ? 1 : 0; |
339 | 341 | } |
340 | 342 | |
343 | +int probe_http_method(const char *p, const char *opt) | |
344 | +{ | |
345 | + return !strncmp(p, opt, strlen(opt)-1); | |
346 | +} | |
341 | 347 | |
348 | +/* Is the buffer the beginnin of an HTTP connection? */ | |
349 | +int is_http_protocol(const char *p, int len) | |
350 | +{ | |
351 | + /* If it's got HTTP in the request (HTTP/1.1) then it's HTTP */ | |
352 | + if (strstr(p, "HTTP")) | |
353 | + return 1; | |
354 | + | |
355 | + /* Otherwise it could be HTTP/1.0 without version: check if it's got an | |
356 | + * HTTP method (RFC2616 5.1.1) */ | |
357 | + probe_http_method(p, "OPTIONS"); | |
358 | + probe_http_method(p, "GET"); | |
359 | + probe_http_method(p, "HEAD"); | |
360 | + probe_http_method(p, "POST"); | |
361 | + probe_http_method(p, "PUT"); | |
362 | + probe_http_method(p, "DELETE"); | |
363 | + probe_http_method(p, "TRACE"); | |
364 | + probe_http_method(p, "CONNECT"); | |
365 | + | |
366 | + return 0; | |
367 | +} | |
368 | + | |
369 | + | |
342 | 370 | /* |
343 | 371 | * Read the beginning of data coming from the client connection and check if |
344 | 372 | * it's a known protocol. Then leave the data on the defered |
345 | 373 | * write buffer of the connection and returns the protocol index in the |
@@ -391,10 +419,20 @@ | ||
391 | 419 | serv, sizeof(serv), |
392 | 420 | numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 ); |
393 | 421 | |
394 | 422 | if (res) { |
395 | - fprintf(stderr, "sprintaddr:getnameinfo: %s\n", gai_strerror(res)); | |
396 | - exit(1); | |
423 | + log_message(LOG_ERR, "sprintaddr:getnameinfo: %s\n", gai_strerror(res)); | |
424 | + /* Name resolution failed: do it numerically instead */ | |
425 | + res = getnameinfo(a->ai_addr, a->ai_addrlen, | |
426 | + host, sizeof(host), | |
427 | + serv, sizeof(serv), | |
428 | + NI_NUMERICHOST | NI_NUMERICSERV); | |
429 | + /* should not fail but... */ | |
430 | + if (res) { | |
431 | + log_message(LOG_ERR, "sprintaddr:getnameinfo(NUM): %s\n", gai_strerror(res)); | |
432 | + strcpy(host, "?"); | |
433 | + strcpy(serv, "?"); | |
434 | + } | |
397 | 435 | } |
398 | 436 | |
399 | 437 | snprintf(buf, size, "%s:%s", host, serv); |
400 | 438 | |
@@ -435,20 +473,18 @@ | ||
435 | 473 | exit(4); |
436 | 474 | } |
437 | 475 | } |
438 | 476 | |
439 | -/* Log to syslog, and to stderr if foreground */ | |
477 | +/* Log to syslog or stderr if foreground */ | |
440 | 478 | void log_message(int type, char* msg, ...) |
441 | 479 | { |
442 | 480 | va_list ap; |
443 | 481 | |
444 | 482 | va_start(ap, msg); |
445 | - vsyslog(type, msg, ap); | |
446 | - va_end(ap); | |
447 | - | |
448 | - va_start(ap, msg); | |
449 | 483 | if (foreground) |
450 | 484 | vfprintf(stderr, msg, ap); |
485 | + else | |
486 | + vsyslog(type, msg, ap); | |
451 | 487 | va_end(ap); |
452 | 488 | } |
453 | 489 | |
454 | 490 | /* syslogs who connected to where */ |
scripts/etc.default.sslh | ||
---|---|---|
@@ -1,3 +1,5 @@ | ||
1 | 1 | LISTEN=ifname:443 |
2 | 2 | SSH=localhost:22 |
3 | 3 | SSL=localhost:443 |
4 | +USER=nobody | |
5 | +PID=/var/run/sslh.pid |
scripts/etc.init.d.sslh | ||
---|---|---|
@@ -12,13 +12,8 @@ | ||
12 | 12 | facility=user.info |
13 | 13 | |
14 | 14 | # /etc/init.d/sslh: start and stop the sslh proxy daemon |
15 | 15 | |
16 | -# Defaults -- can be overridden in /etc/default/sslh | |
17 | -LISTEN=thelonious:443 | |
18 | -SSH=localhost:22 | |
19 | -SSL=localhost:443 | |
20 | - | |
21 | 16 | if test -f /etc/default/sslh; then |
22 | 17 | . /etc/default/sslh |
23 | 18 | fi |
24 | 19 | |
@@ -29,9 +24,9 @@ | ||
29 | 24 | |
30 | 25 | start() |
31 | 26 | { |
32 | 27 | echo "Start services: sslh" |
33 | - $DAEMON --user nobody --listen ${LISTEN} --ssh ${SSH} --ssl ${SSL} | |
28 | + $DAEMON --user ${USER} --pidfile ${PID} --listen ${LISTEN} --ssh ${SSH} --ssl ${SSL} | |
34 | 29 | logger -t ${tag} -p ${facility} -i 'Started sslh' |
35 | 30 | } |
36 | 31 | |
37 | 32 | stop() |
scripts/etc.rc.d.init.d.sslh.centos | ||
---|---|---|
@@ -19,9 +19,9 @@ | ||
19 | 19 | |
20 | 20 | SSLH="/usr/local/sbin/sslh" |
21 | 21 | PIDFILE="/var/run/sslh" |
22 | 22 | |
23 | -OPTIONS="-p 0.0.0.0:8443 --ssl 127.0.0.1:443 --ssh 127.0.0.1:22" | |
23 | +OPTIONS="--user nobody --pidfile $PIDFILE -p 0.0.0.0:8443 --ssl 127.0.0.1:443 --ssh 127.0.0.1:22" | |
24 | 24 | |
25 | 25 | if [ -f /etc/sysconfig/sslh ]; then |
26 | 26 | . /etc/sysconfig/sslh |
27 | 27 | fi |
sslh-fork.c | ||
---|---|---|
@@ -137,8 +137,9 @@ | ||
137 | 137 | { |
138 | 138 | int in_socket, i, res; |
139 | 139 | struct sigaction action; |
140 | 140 | |
141 | + listener_pid_number = num_addr_listen; | |
141 | 142 | listener_pid = malloc(listener_pid_number * sizeof(listener_pid[0])); |
142 | 143 | |
143 | 144 | /* Start one process for each listening address */ |
144 | 145 | for (i = 0; i < num_addr_listen; i++) { |
@@ -169,9 +170,8 @@ | ||
169 | 170 | action.sa_handler = stop_listeners; |
170 | 171 | res = sigaction(SIGTERM, &action, NULL); |
171 | 172 | CHECK_RES_DIE(res, "sigaction"); |
172 | 173 | |
173 | - listener_pid_number = num_addr_listen; | |
174 | 174 | wait(NULL); |
175 | 175 | } |
176 | 176 | |
177 | 177 | /* The actual main is in common.c: it's the same for both version of |
sslh-main.c | ||
---|---|---|
@@ -153,10 +153,10 @@ | ||
153 | 153 | |
154 | 154 | int *listen_sockets; |
155 | 155 | |
156 | 156 | /* Init defaults */ |
157 | - pid_file = "/var/run/sslh.pid"; | |
158 | - user_name = "nobody"; | |
157 | + pid_file = NULL; | |
158 | + user_name = NULL; | |
159 | 159 | foreground = 0; |
160 | 160 | |
161 | 161 | parse_cmdline(argc, argv); |
162 | 162 | |
@@ -171,23 +171,26 @@ | ||
171 | 171 | printsettings(); |
172 | 172 | |
173 | 173 | num_addr_listen = start_listen_sockets(&listen_sockets, addr_listen); |
174 | 174 | |
175 | - if (!foreground) | |
175 | + if (!foreground) { | |
176 | 176 | if (fork() > 0) exit(0); /* Detach */ |
177 | 177 | |
178 | + /* New session -- become group leader */ | |
179 | + if (getuid() == 0) { | |
180 | + res = setsid(); | |
181 | + CHECK_RES_DIE(res, "setsid: already process leader"); | |
182 | + } | |
183 | + } | |
184 | + | |
178 | 185 | setup_signals(); |
179 | 186 | |
180 | - drop_privileges(user_name); | |
187 | + if (user_name) | |
188 | + drop_privileges(user_name); | |
181 | 189 | |
182 | - /* New session -- become group leader */ | |
183 | - if (getuid() == 0) { | |
184 | - res = setsid(); | |
185 | - CHECK_RES_DIE(res, "setsid: already process leader"); | |
186 | - } | |
190 | + if (pid_file) | |
191 | + write_pid_file(pid_file); | |
187 | 192 | |
188 | - write_pid_file(pid_file); | |
189 | - | |
190 | 193 | /* Open syslog connection */ |
191 | 194 | setup_syslog(argv[0]); |
192 | 195 | |
193 | 196 | main_loop(listen_sockets, num_addr_listen); |
sslh.pod | ||
---|---|---|
@@ -5,17 +5,17 @@ | ||
5 | 5 | sslh - ssl/ssh multiplexer |
6 | 6 | |
7 | 7 | =head1 SYNOPSIS |
8 | 8 | |
9 | -sslh [ B<-t> I<num> ] [B<-p> I<listening address> [B<-p> I<listening address> ...] [B<--ssl> I<target address for SSL>] [B<--ssh> I<target address for SSH>] [B<--openvpn> I<target address for OpenVPN>] [B<-u> I<username>] [B<-P> I<pidfile>] [-v] [-i] [-V] [-f] [-n] | |
9 | +sslh [ B<-t> I<num> ] [B<-p> I<listening address> [B<-p> I<listening address> ...] [B<--ssl> I<target address for SSL>] [B<--ssh> I<target address for SSH>] [B<--openvpn> I<target address for OpenVPN>] [B<--http> I<target address for HTTP>] [B<-u> I<username>] [B<-P> I<pidfile>] [-v] [-i] [-V] [-f] [-n] | |
10 | 10 | |
11 | 11 | =head1 DESCRIPTION |
12 | 12 | |
13 | -B<sslh> accepts HTTPS, SSH, OpenVPN, tinc and XMPP connections | |
14 | -on the same port. This makes it possible to connect to any | |
15 | -of these servers on port 443 (e.g. from inside a corporate | |
16 | -firewall, which almost never block port 443) while still | |
17 | -serving HTTPS on that port. | |
13 | +B<sslh> accepts HTTP, HTTPS, SSH, OpenVPN, tinc and XMPP | |
14 | +connections on the same port. This makes it possible to | |
15 | +connect to any of these servers on port 443 (e.g. from | |
16 | +inside a corporate firewall, which almost never block port | |
17 | +443) while still serving HTTPS on that port. | |
18 | 18 | |
19 | 19 | |
20 | 20 | The idea is to have B<sslh> listen to the external 443 port, |
21 | 21 | accept the incoming connections, work out what type of |
@@ -122,16 +122,14 @@ | ||
122 | 122 | Prints B<sslh> version. |
123 | 123 | |
124 | 124 | =item B<-u> I<username>, B<--user> I<username> |
125 | 125 | |
126 | -Requires to run under the specified username. Defaults to | |
127 | -I<nobody> (which is not perfect -- ideally B<sslh> should | |
128 | -run under its own UID). | |
126 | +Requires to run under the specified username. | |
129 | 127 | |
130 | 128 | =item B<-P> I<pidfile>, B<--pid-file> I<pidfile> |
131 | 129 | |
132 | -Specifies the file in which to write the PID of the main | |
133 | -server. Defaults to I</var/run/sslh.pid>. | |
130 | +Specifies a file in which to write the PID of the main | |
131 | +server. | |
134 | 132 | |
135 | 133 | =item B<-i>, B<--inetd> |
136 | 134 | |
137 | 135 | Runs as an I<inetd> server. Options B<-P> (PID file), B<-p> |
Built with git-ssb-web