git ssb

0+

cel / sslh



Commit a9c9941988bfa759887061f9e11fd09b67bd0f38

v1.9: 02AUG2011

	WARNING: Options changed, you'll need to update your
	start-up scripts! Log format changed, you'll need to
	update log processing scripts!

	Now supports IPv6 throughout (both on listening and
	forwarding)

	Logs now contain IPv6 addresses, local forwarding
	address, and resolves names (unless --numeric is
	specified).

	Introduced long options.

	Options -l, -s and -o replaced by their long
	counterparts.

	Defaults for SSL and SSH options suppressed (it's
	legitimate to want to use sslh to mux OpenVPN and
	tinc while not caring about SSH nor SSL).

	Bind to multiple addresses with multiple -p options.

	Support for tinc VPN (experimental).

	Numeric logging option.
Yves Rutschle committed on 7/10/2013, 9:13:32 PM
Parent: 80f76c6fc58f4ae5c3d25f42017a11d4918e1502

Files changed

ChangeLogchanged
Makefilechanged
READMEchanged
common.cchanged
common.hchanged
scripts/etc.init.d.sslhchanged
scripts/etc.rc.d.init.d.sslh.centoschanged
sslh-fork.cchanged
sslh-select.cchanged
sslh.podchanged
ChangeLogView
@@ -1,5 +1,32 @@
1-v1.8:
1+v1.9: 02AUG2011
2+ WARNING: Options changed, you'll need to update your
3+ start-up scripts! Log format changed, you'll need to
4+ update log processing scripts!
5+
6+ Now supports IPv6 throughout (both on listening and
7+ forwarding)
8+
9+ Logs now contain IPv6 addresses, local forwarding
10+ address, and resolves names (unless --numeric is
11+ specified).
12+
13+ Introduced long options.
14+
15+ Options -l, -s and -o replaced by their long
16+ counterparts.
17+
18+ Defaults for SSL and SSH options suppressed (it's
19+ legitimate to want to use sslh to mux OpenVPN and
20+ tinc while not caring about SSH nor SSL).
21+
22+ Bind to multiple addresses with multiple -p options.
23+
24+ Support for tinc VPN (experimental).
25+
26+ Numeric logging option.
27+
28+v1.8: 15JUL2011
229 Changed log format to make it possible to link
330 connections to subsequent logs from other services.
431
532 Updated CentOS init.d script (Andre Krajnik).
MakefileView
@@ -1,7 +1,7 @@
11 # Configuration
22
3-VERSION="v1.8"
3+VERSION="v1.9"
44 USELIBWRAP= # Use libwrap?
55 PREFIX=/usr/local
66
77 MAN=sslh.8.gz # man page name
@@ -28,13 +28,13 @@
2828
2929
3030 sslh: $(OBJS) sslh-fork sslh-select
3131
32-sslh-fork: $(OBJS) sslh-fork.o Makefile
32+sslh-fork: $(OBJS) sslh-fork.o Makefile common.h
3333 $(CC) $(CFLAGS) -D'VERSION=$(VERSION)' -o sslh-fork sslh-fork.o $(OBJS) $(LIBS)
3434 strip sslh-fork
3535
36-sslh-select: $(OBJS) sslh-select.o Makefile
36+sslh-select: $(OBJS) sslh-select.o Makefile common.h
3737 $(CC) $(CFLAGS) -D'VERSION=$(VERSION)' -o sslh-select sslh-select.o $(OBJS) $(LIBS)
3838 strip sslh-select
3939
4040
READMEView
@@ -103,24 +103,24 @@
103103 In that case, you end up with something like this:
104104
105105 ssh -> proxytunnel -e --------ssh/ssl------> stunnel ---ssh---> sslh --> sshd
106106
107-navigateur --------http/ssl------> stunnel ---http---> sslh --> http:80
107+Web browser --------http/ssl------> stunnel ---http---> sslh --> http:80
108108
109109 Configuration goes like this:
110110
111111 On the server side, using stunnel3:
112-stunnel -f -p mycert.pem -d thelonious:443 -l /usr/local/sbin/sslh -- sslh -i -l localhost:80 -s localhost:22
112+stunnel -f -p mycert.pem -d thelonious:443 -l /usr/local/sbin/sslh -- sslh -i --ssl localhost:80 --ssh localhost:22
113113
114114 stunnel options: -f for foreground/debugging, -p specifies
115115 the key + certificate, -d specifies which interface and port
116116 we're listening to for incoming connexions, -l summons sslh
117117 in inetd mode.
118118
119-sslh options: -i for inetd mode, -l to forward SSL
119+sslh options: -i for inetd mode, --ssl to forward SSL
120120 connexions (in fact normal HTTP at that stage) to port 80,
121121 and SSH connexions to port 22. This works because sslh
122-considers that anything that is not SSH is SSL.
122+considers that any protocol it doesn't recognise is SSL.
123123
124124 ==== IP_TPROXY support ====
125125
126126 There is a netfilter patch that adds an option to the Linux
common.cView
@@ -20,8 +20,9 @@
2020 #include <netdb.h>
2121 #include <pwd.h>
2222 #include <syslog.h>
2323 #include <libgen.h>
24+#include <getopt.h>
2425
2526 #include "common.h"
2627
2728 /* Added to make the code compilable under CYGWIN
@@ -31,33 +32,36 @@
3132 #endif
3233
3334 int is_ssh_protocol(const char *p, int len);
3435 int is_openvpn_protocol(const char *p, int len);
36+int is_tinc_protocol(const char *p, int len);
3537 int is_true(const char *p, int len) { return 1; }
3638
3739 struct proto protocols[] = {
3840 /* affected description service saddr probe */
39- { 0, "SSH", "sshd", {0}, is_ssh_protocol },
40- { 0, "OpenVPN", NULL, {0}, is_openvpn_protocol },
41+ { 0, "ssh", "sshd", {0}, is_ssh_protocol },
42+ { 0, "openvpn", NULL, {0}, is_openvpn_protocol },
43+ { 0, "tinc", NULL, {0}, is_tinc_protocol },
4144 /* probe for SSL always successes: it's the default, and must be tried last
4245 **/
43- { 0, "SSL", NULL, {0}, is_true }
46+ { 0, "ssl", NULL, {0}, is_true }
4447 };
4548
4649
4750 const char* USAGE_STRING =
4851 "sslh " VERSION "\n" \
4952 "usage:\n" \
50-"\tsslh [-v] [-i] [-V] [-f]"
51-"[-t <timeout>] -u <username> -p [listenaddr:]<listenport> \n" \
52-"\t\t-s [sshhost:]port -l [sslhost:]port [-P pidfile]\n\n" \
53+"\tsslh [-v] [-i] [-V] [-f]\n"
54+"\t[-t <timeout>] [-P <pidfile>] -u <username> -p <add> [-p <addr> ...] \n" \
55+"\t[--ssh <addr>] [--ssl <addr>] [--openvpn <addr>] [--tinc <addr>]\n\n" \
5356 "-v: verbose\n" \
5457 "-V: version\n" \
5558 "-f: foreground\n" \
56-"-p: address and port to listen on. default: 0.0.0.0:443\n" \
57-"-s: SSH address: where to connect an SSH connection. default: localhost:22\n" \
58-"-l: SSL address: where to connect an SSL connection.\n" \
59-"-o: OpenVPN address: where to connect an OpenVPN connection.\n" \
59+"-p: address and port to listen on. default: 0.0.0.0:443.\n Can be used several times to bind to several addresses.\n" \
60+"--ssh: SSH address: where to connect an SSH connection.\n" \
61+"--ssl: SSL address: where to connect an SSL connection.\n" \
62+"--openvpn: OpenVPN address: where to connect an OpenVPN connection.\n" \
63+"--tinc: tinc address: where to connect a tinc connection.\n" \
6064 "-P: PID file. Default: /var/run/sslh.pid.\n" \
6165 "-i: Run as a inetd service.\n" \
6266 "";
6367
@@ -70,40 +74,61 @@
7074 int verbose = 0;
7175 int probing_timeout = 2;
7276 int inetd = 0;
7377 int foreground = 0;
74-struct sockaddr addr_listen;
78+int numeric = 0;
7579 char *user_name, *pid_file;
7680
81+struct sockaddr_storage *addr_listen = NULL; /* what addresses do we listen to? */
82+int num_addr_listen = 0; /* How many addresses do we listen to? */
83+
7784 #ifdef LIBWRAP
7885 #include <tcpd.h>
7986 int allow_severity =0, deny_severity = 0;
8087 #endif
8188
8289
90+/* check result and die, printing the offending address and error */
91+void check_res_dumpdie(int res, struct sockaddr_storage *sock, char* syscall)
92+{
93+ char buf[64];
8394
84-/* Starts a listening socket on specified address.
95+ if (res == -1) {
96+ fprintf(stderr, "%s:%s: %s\n",
97+ sprintaddr(buf, sizeof(buf), sock),
98+ syscall,
99+ strerror(errno));
100+ exit(1);
101+ }
102+}
103+
104+/* Starts listening sockets on specified addresses.
105+ * IN: addr[], num_addr
106+ * OUT: sockfd[]
107+ * Bound file descriptors are returned in alread-allocated *sockfd pointer
85108 Returns file descriptor
86109 */
87-int start_listen_socket(struct sockaddr *addr)
110+void start_listen_sockets(int sockfd[], struct sockaddr_storage addr[], int num_addr)
88111 {
89- struct sockaddr_in *saddr = (struct sockaddr_in*)addr;
90- int sockfd, res, reuse;
112+ struct sockaddr_storage *saddr;
113+ int i, res, reuse;
91114
92- sockfd = socket(AF_INET, SOCK_STREAM, 0);
93- CHECK_RES_DIE(sockfd, "socket");
115+ for (i = 0; i < num_addr; i++) {
116+ saddr = &addr[i];
94117
95- reuse = 1;
96- res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
97- CHECK_RES_DIE(res, "setsockopt");
118+ sockfd[i] = socket(saddr->ss_family, SOCK_STREAM, 0);
119+ check_res_dumpdie(sockfd[i], saddr, "socket");
98120
99- res = bind (sockfd, (struct sockaddr*)saddr, sizeof(*saddr));
100- CHECK_RES_DIE(res, "bind");
121+ reuse = 1;
122+ res = setsockopt(sockfd[i], SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
123+ check_res_dumpdie(res, saddr, "setsockopt");
101124
102- res = listen (sockfd, 50);
103- CHECK_RES_DIE(res, "listen");
125+ res = bind (sockfd[i], (struct sockaddr*)saddr, sizeof(*saddr));
126+ check_res_dumpdie(res, saddr, "bind");
104127
105- return sockfd;
128+ res = listen (sockfd[i], 50);
129+ check_res_dumpdie(res, saddr, "listen");
130+ }
106131 }
107132
108133 /* Store some data to write to the queue later */
109134 int defer_write(struct queue *q, void* data, int data_size)
@@ -259,8 +284,15 @@
259284 else
260285 return 0;
261286 }
262287
288+/* Is the buffer the beginning of a tinc connections?
289+ * (protocol is undocumented, but starts with "0 " in 1.0.15)
290+ * */
291+int is_tinc_protocol( const char *p, int len)
292+{
293+ return !strncmp(p, "0 ", len);
294+}
263295
264296 /*
265297 * Read the beginning of data coming from the client connection and check if
266298 * it's a known protocol. Then leave the data on the defered
@@ -289,48 +321,55 @@
289321 }
290322 }
291323 }
292324
293- /* If none worked, return the last one */
294- return ARRAY_SIZE(protocols) - 1;
325+ /* If none worked, return the first one affected (that's completely
326+ * arbitrary) */
327+ for (i = 0; i < ARRAY_SIZE(protocols); i++)
328+ if (protocols[i].affected)
329+ return i;
330+
331+ /* At this stage... nothing is affected. This shouldn't happen as we check
332+ * at least one target exists when we parse the commnand line */
333+ fprintf(stderr, "FATAL: No protocol affected. This should not happen.\n");
334+ exit(1);
295335 }
296336
297337 /* returns a string that prints the IP and port of the sockaddr */
298-char* sprintaddr(char* buf, size_t size, struct sockaddr* s)
338+char* sprintaddr(char* buf, size_t size, struct sockaddr_storage* s)
299339 {
300- char addr_str[1024];
340+ char host[NI_MAXHOST], serv[NI_MAXSERV];
301341
302- inet_ntop(AF_INET, &((struct sockaddr_in*)s)->sin_addr, addr_str, sizeof(addr_str));
303- snprintf(buf, size, "%s:%d", addr_str, ntohs(((struct sockaddr_in*)s)->sin_port));
342+ getnameinfo((struct sockaddr*)s, sizeof(*s), host, sizeof(host), serv, sizeof(serv), numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 );
343+ snprintf(buf, size, "%s:%s", host, serv);
344+
304345 return buf;
305346 }
306347
307348 /* turns a "hostname:port" string into a struct sockaddr;
308349 sock: socket address to which to copy the addr
309350 fullname: input string -- it gets clobbered
310351 */
311-void resolve_name(struct sockaddr *sock, char* fullname)
352+void resolve_name(struct sockaddr_storage *sock, char* fullname)
312353 {
313354 struct addrinfo *addr, hint;
314355 char *serv, *host;
315356 int res;
316357
317- char *sep = strchr(fullname, ':');
358+ char *sep = strrchr(fullname, ':');
318359
319360 if (!sep) /* No separator: parameter is just a port */
320361 {
321- serv = fullname;
322362 fprintf(stderr, "names must be fully specified as hostname:port\n");
323363 exit(1);
324364 }
325- else {
326- host = fullname;
327- serv = sep+1;
328- *sep = 0;
329- }
330365
366+ host = fullname;
367+ serv = sep+1;
368+ *sep = 0;
369+
331370 memset(&hint, 0, sizeof(hint));
332- hint.ai_family = PF_INET;
371+ hint.ai_family = PF_UNSPEC;
333372 hint.ai_socktype = SOCK_STREAM;
334373
335374 res = getaddrinfo(host, serv, &hint, &addr);
336375 if (res) {
@@ -362,22 +401,43 @@
362401
363402 /* syslogs who connected to where */
364403 void log_connection(struct connection *cnx)
365404 {
366- struct sockaddr peeraddr, localaddr;
405+ struct sockaddr_storage peeraddr; /* Who's connecting to sshd */
406+ struct sockaddr_storage listenaddr; /* Where is it connecting to */
407+ struct sockaddr_storage forwardfromaddr; /* Where is it forwarded from */
408+ struct sockaddr_storage targetaddr; /* Where is it forwarded to */
367409 socklen_t size = sizeof(peeraddr);
368- char buf[64], buf2[64];
410+#define MAX_NAMELENGTH (NI_MAXHOST + NI_MAXSERV + 1)
411+ char buf[MAX_NAMELENGTH], buf2[MAX_NAMELENGTH], buf3[MAX_NAMELENGTH], buf4[MAX_NAMELENGTH];
369412 int res;
370413
371- res = getpeername(cnx->q[0].fd, &peeraddr, &size);
372- if (res == -1) return; /* that should never happen, right? */
414+ memset(&peeraddr, 0, sizeof(peeraddr));
415+ memset(&listenaddr, 0, sizeof(listenaddr));
416+ memset(&forwardfromaddr, 0, sizeof(forwardfromaddr));
417+ memset(&targetaddr, 0, sizeof(targetaddr));
373418
374- res = getpeername(cnx->q[1].fd, &localaddr, &size);
419+ res = getpeername(cnx->q[0].fd, (struct sockaddr*)&peeraddr, &size);
375420 if (res == -1) return; /* that should never happen, right? */
376421
377- log_message(LOG_INFO, "connection from %s forwarded to %s\n",
378- sprintaddr(buf, sizeof(buf), &peeraddr), sprintaddr(buf2, sizeof(buf2), &localaddr));
422+ size = sizeof(listenaddr);
423+ res = getsockname(cnx->q[0].fd, (struct sockaddr*)&listenaddr, &size);
424+ if (res == -1) return;
379425
426+ size = sizeof(targetaddr);
427+ res = getpeername(cnx->q[1].fd, (struct sockaddr*)&targetaddr, &size);
428+ if (res == -1) return;
429+
430+ size = sizeof(forwardfromaddr);
431+ res = getsockname(cnx->q[1].fd, (struct sockaddr*)&forwardfromaddr, &size);
432+ if (res == -1) return;
433+
434+ log_message(LOG_INFO, "connection from %s to %s forwarded from %s to %s\n",
435+ sprintaddr(buf, sizeof(buf), &peeraddr),
436+ sprintaddr(buf2, sizeof(buf2), &listenaddr),
437+ sprintaddr(buf3, sizeof(buf3), &forwardfromaddr),
438+ sprintaddr(buf4, sizeof(buf4), &targetaddr));
439+
380440 }
381441
382442
383443 /* libwrap (tcpd): check the connection is legal. This is necessary because
@@ -385,29 +445,40 @@
385445 * apply the rules itself.
386446 *
387447 * Returns -1 if access is denied, 0 otherwise
388448 */
389-int check_access_rights(int in_socket, const char* service)
449+int check_access_rights(int in_socket, char* service)
390450 {
391451 #ifdef LIBWRAP
392452 struct sockaddr peeraddr;
393453 socklen_t size = sizeof(peeraddr);
394- char addr_str[1024];
395- struct hostent *host;
396- struct in_addr addr;
454+ char addr_str[NI_MAXHOST], host[NI_MAXHOST];
397455 int res;
398456
399457 res = getpeername(in_socket, &peeraddr, &size);
400458 CHECK_RES_DIE(res, "getpeername");
401- inet_ntop(AF_INET, &((struct sockaddr_in*)&peeraddr)->sin_addr, addr_str, sizeof(addr_str));
402459
403- addr.s_addr = inet_addr(addr_str);
404- host = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
460+ /* extract peer address */
461+ res = getnameinfo(&peeraddr, size, addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST);
462+ if (res) {
463+ if (verbose)
464+ fprintf(stderr, "getnameinfo(NI_NUMERICHOST):%s\n", gai_strerror(res));
465+ strcpy(addr_str, STRING_UNKNOWN);
466+ }
467+ /* extract peer name */
468+ strcpy(host, STRING_UNKNOWN);
469+ if (!numeric) {
470+ res = getnameinfo(&peeraddr, size, host, sizeof(host), NULL, 0, NI_NAMEREQD);
471+ if (res) {
472+ if (verbose)
473+ fprintf(stderr, "getnameinfo(NI_NAMEREQD):%s\n", gai_strerror(res));
474+ }
475+ }
405476
406- if (!hosts_ctl(service, (host ? host->h_name : STRING_UNKNOWN), addr_str, STRING_UNKNOWN)) {
477+ if (!hosts_ctl(service, host, addr_str, STRING_UNKNOWN)) {
407478 if (verbose)
408479 fprintf(stderr, "access denied\n");
409- log_connection(in_socket, "access denied");
480+ log_message(LOG_INFO, "connection from %s(%s): access denied", host, addr_str);
410481 close(in_socket);
411482 return -1;
412483 }
413484 #endif
@@ -488,53 +559,76 @@
488559 protocols[i].description,
489560 sprintaddr(buf, sizeof(buf), &protocols[i].saddr),
490561 protocols[i].service);
491562 }
492- fprintf(stderr, "listening on %s\n", sprintaddr(buf, sizeof(buf), &addr_listen));
563+ fprintf(stderr, "listening on:\n");
564+ for (i = 0; i < num_addr_listen; i++) {
565+ fprintf(stderr, "\t%s\n", sprintaddr(buf, sizeof(buf), &addr_listen[i]));
566+ }
567+ fprintf(stderr, "timeout to ssh: %d\n", probing_timeout);
493568 }
494569
570+/* Adds protocols to the list of options, so command-line parsing uses the
571+ * protocol definition array
572+ * options: array of options to add to; must be big enough
573+ * n_opts: number of options in *options before calling (i.e. where to append)
574+ * prot: array of protocols
575+ * n_prots: number of protocols in *prot
576+ * */
577+#define PROT_SHIFT 1000 /* protocol options will be 1000, 1001, etc */
578+void append_protocols(struct option *options, int n_opts, struct proto *prot, int n_prots)
579+{
580+ int o, p;
581+
582+ for (o = n_opts, p = 0; p < n_prots; o++, p++) {
583+ options[o].name = prot[p].description;
584+ options[o].has_arg = required_argument;
585+ options[o].flag = 0;
586+ options[o].val = p + PROT_SHIFT;
587+ }
588+}
589+
495590 void parse_cmdline(int argc, char* argv[])
496591 {
497- int c;
592+ int c, affected = 0;
593+ struct option const_options[] = {
594+ { "inetd", no_argument, &inetd, 1 },
595+ { "foreground", no_argument, &foreground, 1 },
596+ { "verbose", no_argument, &verbose, 1 },
597+ { "numeric", no_argument, &numeric, 1 },
598+ { "user", required_argument, 0, 'u' },
599+ { "pidfile", required_argument, 0, 'P' },
600+ { "timeout", required_argument, 0, 't' },
601+ { "listen", required_argument, 0, 'p' },
602+ };
603+ struct option all_options[ARRAY_SIZE(const_options) + ARRAY_SIZE(protocols) + 1];
498604
499- while ((c = getopt(argc, argv, "t:l:s:o:p:P:ivfVu:")) != EOF) {
605+ memset(all_options, 0, sizeof(all_options));
606+ memcpy(all_options, const_options, sizeof(const_options));
607+ append_protocols(all_options, ARRAY_SIZE(const_options), protocols, ARRAY_SIZE(protocols));
608+
609+ while ((c = getopt_long_only(argc, argv, "t:l:s:o:T:p:VP:", all_options, NULL)) != -1) {
610+ if (c == 0) continue;
611+
612+ if (c >= PROT_SHIFT) {
613+ affected++;
614+ protocols[c - PROT_SHIFT].affected = 1;
615+ resolve_name(&protocols[c - PROT_SHIFT].saddr, optarg);
616+ continue;
617+ }
618+
500619 switch (c) {
501620
502621 case 't':
503622 probing_timeout = atoi(optarg);
504623 break;
505624
506625 case 'p':
507- resolve_name(&addr_listen, optarg);
626+ num_addr_listen++;
627+ addr_listen = realloc(addr_listen, num_addr_listen * sizeof(addr_listen[0]));
628+ resolve_name(&addr_listen[num_addr_listen - 1], optarg);
508629 break;
509630
510- case 'l':
511- protocols[PROT_SSL].affected = 1;
512- resolve_name(&protocols[PROT_SSL].saddr, optarg);
513- break;
514-
515- case 's':
516- protocols[PROT_SSH].affected = 1;
517- resolve_name(&protocols[PROT_SSH].saddr, optarg);
518- break;
519-
520- case 'o':
521- protocols[PROT_OPENVPN].affected = 1;
522- resolve_name(&protocols[PROT_OPENVPN].saddr, optarg);
523- break;
524-
525- case 'i':
526- inetd = 1;
527- break;
528-
529- case 'f':
530- foreground = 1;
531- break;
532-
533- case 'v':
534- verbose += 1;
535- break;
536-
537631 case 'V':
538632 printf("%s %s\n", server_type, VERSION);
539633 exit(0);
540634
@@ -550,8 +644,19 @@
550644 fprintf(stderr, USAGE_STRING);
551645 exit(2);
552646 }
553647 }
648+
649+ if (!affected) {
650+ fprintf(stderr, "At least one target protocol must be specified.\n");
651+ exit(2);
652+ }
653+
654+ if (!num_addr_listen) {
655+ fprintf(stderr, "No listening address specified; use at least one -p option\n");
656+ exit(1);
657+ }
658+
554659 }
555660
556661 int main(int argc, char *argv[])
557662 {
@@ -559,24 +664,15 @@
559664 extern char *optarg;
560665 extern int optind;
561666 int res;
562667
563- int listen_socket;
668+ int *listen_sockets;
564669
565670 /* Init defaults */
566- char listen_str[] = "0.0.0.0:443";
567- char ssl_str[] = "localhost:443";
568- char ssh_str[] = "localhost:22";
569671 pid_file = "/var/run/sslh.pid";
570672 user_name = "nobody";
571673 foreground = 0;
572674
573- resolve_name(&addr_listen, listen_str);
574- protocols[PROT_SSL].affected = 1;
575- resolve_name(&protocols[PROT_SSL].saddr, ssl_str);
576- protocols[PROT_SSH].affected = 1;
577- resolve_name(&protocols[PROT_SSH].saddr, ssh_str);
578-
579675 parse_cmdline(argc, argv);
580676
581677 if (inetd)
582678 {
@@ -587,9 +683,11 @@
587683
588684 if (verbose)
589685 printsettings();
590686
591- listen_socket = start_listen_socket(&addr_listen);
687+ listen_sockets = malloc(num_addr_listen * sizeof(*listen_sockets));
688+ start_listen_sockets(listen_sockets, addr_listen, num_addr_listen);
689+ free(addr_listen);
592690
593691 if (!foreground)
594692 if (fork() > 0) exit(0); /* Detach */
595693
@@ -607,8 +705,8 @@
607705
608706 /* Open syslog connection */
609707 setup_syslog(argv[0]);
610708
611- main_loop(listen_socket);
709+ main_loop(listen_sockets, num_addr_listen);
612710
613711 return 0;
614712 }
common.hView
@@ -51,17 +51,18 @@
5151 * These must match the order of the protocols[] array in common.c */
5252 typedef enum protocol_type {
5353 PROT_SSH,
5454 PROT_OPENVPN,
55+ PROT_TINC,
5556 PROT_SSL,
5657 } T_PROTO_ID;
5758
5859 /* For each protocol we need: */
5960 struct proto {
6061 int affected; /* are we actually using it? */
61- char* description; /* a string that says what it is (for logging) */
62+ char* description; /* a string that says what it is (for logging and command-line parsing) */
6263 char* service; /* service name to do libwrap checks */
63- struct sockaddr saddr; /* where to switch that protocol */
64+ struct sockaddr_storage saddr; /* where to switch that protocol */
6465 int (*probe)(const char*, int); /* function to probe that protocol */
6566 };
6667
6768 /* A table in common.c contains all the known protocols */
@@ -92,15 +93,15 @@
9293
9394
9495 /* common.c */
9596 void init_cnx(struct connection *cnx);
96-int start_listen_socket(struct sockaddr *addr);
97+void start_listen_sockets(int sockfd[], struct sockaddr_storage addr[], int num_addr);
9798 int fd2fd(struct queue *target, struct queue *from);
99+char* sprintaddr(char* buf, size_t size, struct sockaddr_storage* s);
100+void resolve_name(struct sockaddr_storage *sock, char* fullname) ;
98101 T_PROTO_ID probe_client_protocol(struct connection *cnx);
99-char* sprintaddr(char* buf, size_t size, struct sockaddr* s);
100-void resolve_name(struct sockaddr *sock, char* fullname) ;
101102 void log_connection(struct connection *cnx);
102-int check_access_rights(int in_socket, const char* service);
103+int check_access_rights(int in_socket, char* service);
103104 void setup_signals(void);
104105 void setup_syslog(char* bin_name);
105106 void drop_privileges(char* user_name);
106107 void write_pid_file(char* pidfile);
@@ -113,15 +114,15 @@
113114 int defer_write(struct queue *q, void* data, int data_size);
114115 int flush_defered(struct queue *q);
115116
116117 extern int probing_timeout, verbose, inetd;
117-extern struct sockaddr addr_listen, addr_ssl, addr_ssh, addr_openvpn;
118+extern struct sockaddr_storage *addr_listen, addr_ssl, addr_ssh, addr_openvpn;
118119 extern const char* USAGE_STRING;
119120 extern char* user_name, *pid_file;
120121 extern const char* server_type;
121122
122123 /* sslh-fork.c */
123124 void start_shoveler(int);
124125
125-void main_loop(int);
126+void main_loop(int *listen_sockets, int num_addr_listen);
126127
127128
scripts/etc.init.d.sslhView
@@ -29,9 +29,9 @@
2929
3030 start()
3131 {
3232 echo "Start services: sslh"
33- $DAEMON -u nobody -p ${LISTEN} -s ${SSH} -l ${SSL}
33+ $DAEMON --user nobody --listen ${LISTEN} --ssh ${SSH} --ssl ${SSL}
3434 logger -t ${tag} -p ${facility} -i 'Started sslh'
3535 }
3636
3737 stop()
scripts/etc.rc.d.init.d.sslh.centosView
@@ -19,9 +19,9 @@
1919
2020 SSLH="/usr/local/sbin/sslh"
2121 PIDFILE="/var/run/sslh"
2222
23-OPTIONS="-p 0.0.0.0:8443 -l 127.0.0.1:443 -s 127.0.0.1:22"
23+OPTIONS="-p 0.0.0.0:8443 --ssl 127.0.0.1:443 --ssh 127.0.0.1:22"
2424
2525 if [ -f /etc/sysconfig/sslh ]; then
2626 . /etc/sysconfig/sslh
2727 fi
sslh-fork.cView
@@ -67,9 +67,9 @@
6767 void start_shoveler(int in_socket)
6868 {
6969 fd_set fds;
7070 struct timeval tv;
71- struct sockaddr *saddr;
71+ struct sockaddr_storage *saddr;
7272 int res;
7373 int out_socket;
7474 char *target;
7575 struct connection cnx;
@@ -102,10 +102,10 @@
102102 exit(0);
103103 }
104104
105105 /* Connect the target socket */
106- out_socket = socket(AF_INET, SOCK_STREAM, 0);
107- res = connect(out_socket, saddr, sizeof(addr_ssl));
106+ out_socket = socket(saddr->ss_family, SOCK_STREAM, 0);
107+ res = connect(out_socket, (struct sockaddr*)saddr, sizeof(addr_ssl));
108108 CHECK_RES_DIE(res, "connect");
109109 if (verbose)
110110 fprintf(stderr, "connected to something\n");
111111
@@ -125,25 +125,29 @@
125125
126126 exit(0);
127127 }
128128
129-void main_loop(int listen_socket)
129+void main_loop(int *listen_sockets, int num_addr_listen)
130130 {
131- int in_socket;
131+ int in_socket, i;
132132
133- while (1)
134- {
135- in_socket = accept(listen_socket, 0, 0);
136- if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
133+ for (i = 0; i < num_addr_listen; i++) {
134+ if (!fork()) {
135+ while (1)
136+ {
137+ in_socket = accept(listen_sockets[i], 0, 0);
138+ if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
137139
138- if (!fork())
139- {
140- close(listen_socket);
141- start_shoveler(in_socket);
142- exit(0);
143- }
144- close(in_socket);
145- }
140+ if (!fork())
141+ {
142+ close(listen_sockets[i]);
143+ start_shoveler(in_socket);
144+ exit(0);
145+ }
146+ close(in_socket);
147+ }
148+ }
149+ }
146150 }
147151
148152 /* The actual main is in common.c: it's the same for both version of
149153 * the server
sslh-select.cView
@@ -110,17 +110,17 @@
110110 return in_socket;
111111 }
112112
113113 /* Connect queue 1 of connection to SSL; returns new file descriptor */
114-int connect_queue(struct connection *cnx, struct sockaddr *addr,
114+int connect_queue(struct connection *cnx, struct sockaddr_storage *addr,
115115 char* cnx_name,
116116 fd_set *fds_r, fd_set *fds_w)
117117 {
118118 struct queue *q = &cnx->q[1];
119119 int res;
120120
121- q->fd = socket(AF_INET, SOCK_STREAM, 0);
122- res = connect(q->fd, addr, sizeof(*addr));
121+ q->fd = socket(addr->ss_family, SOCK_STREAM, 0);
122+ res = connect(q->fd, (struct sockaddr*)addr, sizeof(*addr));
123123 log_connection(cnx);
124124 if (res == -1) {
125125 tidy_connection(cnx, fds_r, fds_w);
126126 log_message(LOG_ERR, "forward to %s failed\n", cnx_name);
@@ -187,9 +187,9 @@
187187 *
188188 * That way, each pair of file descriptor (read from one, write to the other)
189189 * is monitored either for read or for write, but never for both.
190190 */
191-void main_loop(int listen_socket)
191+void main_loop(int *listen_sockets, int num_addr_listen)
192192 {
193193 fd_set fds_r, fds_w; /* reference fd sets (used to init the next 2) */
194194 fd_set readfds, writefds; /* working read and write fd sets */
195195 struct timeval tv;
@@ -202,12 +202,14 @@
202202 * select() */
203203
204204 FD_ZERO(&fds_r);
205205 FD_ZERO(&fds_w);
206- FD_SET(listen_socket, &fds_r);
207- max_fd = listen_socket + 1;
208206
209- set_nonblock(listen_socket);
207+ for (i = 0; i < num_addr_listen; i++) {
208+ FD_SET(listen_sockets[i], &fds_r);
209+ set_nonblock(listen_sockets[i]);
210+ }
211+ max_fd = listen_sockets[num_addr_listen-1] + 1;
210212
211213 cnx_num_alloc = getpagesize() / sizeof(struct connection);
212214
213215 num_cnx = cnx_num_alloc; /* Start with a set pool of slots */
@@ -230,18 +232,20 @@
230232 perror("select");
231233
232234
233235 /* Check main socket for new connections */
234- if (FD_ISSET(listen_socket, &readfds)) {
235- in_socket = accept_new_connection(listen_socket, &cnx, &num_cnx);
236- num_probing++;
236+ for (i = 0; i < num_addr_listen; i++) {
237+ if (FD_ISSET(listen_sockets[i], &readfds)) {
238+ in_socket = accept_new_connection(listen_sockets[i], &cnx, &num_cnx);
239+ num_probing++;
237240
238- if (in_socket > 0) {
239- FD_SET(in_socket, &fds_r);
240- if (in_socket >= max_fd)
241- max_fd = in_socket + 1;;
241+ if (in_socket > 0) {
242+ FD_SET(in_socket, &fds_r);
243+ if (in_socket >= max_fd)
244+ max_fd = in_socket + 1;;
245+ }
246+ FD_CLR(listen_sockets[i], &readfds);
242247 }
243- FD_CLR(listen_socket, &readfds);
244248 }
245249
246250 /* Check all sockets for write activity */
247251 for (i = 0; i < num_cnx; i++) {
sslh.podView
@@ -5,9 +5,9 @@
55 sslh - ssl/ssh multiplexer
66
77 =head1 SYNOPSIS
88
9-sslh [ B<-t> I<num> ] [B<-p> I<listening address>] [B<-l> I<target address for SSL>] [B<-s> I<target address for SSH>] [B<-o> I<target address for OpenVPN>] [B<-u> I<username>] [B<-P> I<pidfile>] [-v] [-i] [-V] [-f]
9+sslh [ B<-t> I<num> ] [B<-p> I<listening address> [B<-p> I<listening address> ...] [B<-l> I<target address for SSL>] [B<-s> I<target address for SSH>] [B<-o> I<target address for OpenVPN>] [B<-u> I<username>] [B<-P> I<pidfile>] [-v] [-i] [-V] [-f] [-n]
1010
1111 =head1 DESCRIPTION
1212
1313 B<sslh> accepts HTTPS, SSH and OpenVPN connections on the
@@ -56,71 +56,81 @@
5656 =head1 OPTIONS
5757
5858 =over 4
5959
60-=item B<-t> I<num>
60+=item B<-t> I<num>, B<--timeout> I<num>
6161
6262 Timeout before a connection is considered to be SSH. Default
6363 is 2s.
6464
65-=item B<-p> I<listening address>
65+=item B<-p> I<listening address>, B<--listen> I<listening address>
6666
6767 Interface and port on which to listen, e.g. I<foobar:443>,
6868 where I<foobar> is the name of an interface (typically the
6969 IP address on which the Internet connection ends up).
7070
71-Defaults to I<0.0.0.0:443> (listen to port 443 on all
72-available interfaces).
71+This can be specified several times to bind B<sslh> to
72+several addresses.
7373
74-=item B<-l> I<target address for SSL>
74+=item B<--ssl> I<target address>
7575
7676 Interface and port on which to forward SSL connection,
7777 typically I<localhost:443>.
7878
79-Defaults to I<localhost:443> (this assumes you would
80-configure your B<httpd> process to listen to port 443).
81-
8279 Note that you can set B<sslh> to listen on I<ext_ip:443> and
8380 B<httpd> to listen on I<localhost:443>: this allows clients
8481 inside your network to just connect directly to B<httpd>.
8582
86-=item B<-s> I<target address for SSH>
83+=item B<--ssh> I<target address>
8784
88-Interface and port on which to forward SSH connection,
89-defaults to I<localhost:22>.
85+Interface and port on which to forward SSH connections,
86+typically I<localhost:22>.
9087
91-=item B<-o> I<target address for OpenVPN>
88+=item B<--openvpn> I<target address>
9289
93-Interface and port on which to forward OpenVPN connections.
94-This parameter is optional, and has no default. If not
95-specified, incoming OpenVPN connections will not be detected
96-as such and treated the same as SSL.
90+Interface and port on which to forward OpenVPN connections,
91+typically I<localhost:1194>.
9792
98-=item B<-v>
93+=item B<--tinc> I<target address>
9994
95+Interface and port on which to forward tinc connections,
96+typically I<localhost:655>.
97+
98+This is experimental. If you use this feature, please report
99+the results (even if it works!)
100+
101+=item B<-v>, B<--verbose>
102+
100103 Increase verboseness.
101104
105+=item B<-n>, B<--numeric>
106+
107+Do not attempt to resolve hostnames: logs will contain IP
108+addresses. This is mostly useful if the system's DNS is slow
109+and running the I<sslh-select> variant, as DNS requests will
110+hang all connections.
111+
102112 =item B<-V>
103113
104114 Prints B<sslh> version.
105115
106-=item B<-u> I<username>
116+=item B<-u> I<username>, B<--user> I<username>
107117
108118 Requires to run under the specified username. Defaults to
109119 I<nobody> (which is not perfect -- ideally B<sslh> should
110120 run under its own UID).
111121
112-=item B<-P> I<pidfile>
122+=item B<-P> I<pidfile>, B<--pid-file> I<pidfile>
113123
114124 Specifies the file in which to write the PID of the main
115125 server. Defaults to I</var/run/sslh.pid>.
116126
117-=item B<-i>
127+=item B<-i>, B<--inetd>
118128
119129 Runs as an I<inetd> server. Options B<-P> (PID file), B<-p>
120130 (listen address), B<-u> (user) are ignored.
121131
122-=item B<-f>
132+=item B<-f>, B<--foreground>
123133
124134 Runs in foreground. The server will not fork and will remain connected
125135 to the terminal. Messages normally sent to B<syslog> will also be sent
126136 to I<stderr>.

Built with git-ssb-web