diff --git a/ChangeLog b/ChangeLog index 98d2b19..8c71824 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,29 @@ -v1.10: +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. + +v1.10: 27NOV2011 Fixed calls referring to sockaddr length so they work with FreeBSD. diff --git a/Makefile b/Makefile index a76c938..567d6ae 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Configuration -VERSION="v1.10" +VERSION="v1.11" USELIBWRAP= # Use libwrap? COV_TEST= # Perform test coverage? PREFIX=/usr/local diff --git a/README b/README index 45cfa39..1b3f1d6 100644 --- a/README +++ b/README @@ -1,10 +1,10 @@ ===== sslh -- A ssl/ssh multiplexer. ===== -sslh accepts HTTPS, SSH, OpenVPN, tinc and XMPP connections -on the same port. This makes it possible to connect to any -of these servers on port 443 (e.g. from inside a corporate -firewall, which almost never block port 443) while still -serving HTTPS on that port. +sslh accepts HTTP, HTTPS, SSH, OpenVPN, tinc and XMPP +connections on the same port. This makes it possible to +connect to any of these servers on port 443 (e.g. from +inside a corporate firewall, which almost never block port +443) while still serving HTTPS on that port. ==== Compile and install ==== diff --git a/common.c b/common.c index 58ac7df..90f7018 100755 --- a/common.c +++ b/common.c @@ -35,6 +35,7 @@ int is_ssh_protocol(const char *p, int len); int is_openvpn_protocol(const char *p, int len); int is_tinc_protocol(const char *p, int len); int is_xmpp_protocol(const char *p, int len); +int is_http_protocol(const char *p, int len); int is_true(const char *p, int len) { return 1; } /* Table of all the protocols we know how to connect to. @@ -51,6 +52,7 @@ struct proto protocols[] = { { 0, "openvpn", NULL, {0}, is_openvpn_protocol }, { 0, "tinc", NULL, {0}, is_tinc_protocol }, { 0, "xmpp", NULL, {0}, is_xmpp_protocol }, + { 0, "http", NULL, {0}, is_http_protocol }, /* probe for SSL always successes: it's the default, and must be tried last **/ { 0, "ssl", NULL, {0}, is_true } @@ -338,6 +340,32 @@ int is_xmpp_protocol( const char *p, int len) return strstr(p, "jabber") ? 1 : 0; } +int probe_http_method(const char *p, const char *opt) +{ + return !strncmp(p, opt, strlen(opt)-1); +} + +/* Is the buffer the beginnin of an HTTP connection? */ +int is_http_protocol(const char *p, int len) +{ + /* If it's got HTTP in the request (HTTP/1.1) then it's HTTP */ + if (strstr(p, "HTTP")) + return 1; + + /* Otherwise it could be HTTP/1.0 without version: check if it's got an + * HTTP method (RFC2616 5.1.1) */ + probe_http_method(p, "OPTIONS"); + probe_http_method(p, "GET"); + probe_http_method(p, "HEAD"); + probe_http_method(p, "POST"); + probe_http_method(p, "PUT"); + probe_http_method(p, "DELETE"); + probe_http_method(p, "TRACE"); + probe_http_method(p, "CONNECT"); + + return 0; +} + /* * Read the beginning of data coming from the client connection and check if @@ -392,8 +420,18 @@ char* sprintaddr(char* buf, size_t size, struct addrinfo *a) numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 ); if (res) { - fprintf(stderr, "sprintaddr:getnameinfo: %s\n", gai_strerror(res)); - exit(1); + log_message(LOG_ERR, "sprintaddr:getnameinfo: %s\n", gai_strerror(res)); + /* Name resolution failed: do it numerically instead */ + res = getnameinfo(a->ai_addr, a->ai_addrlen, + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV); + /* should not fail but... */ + if (res) { + log_message(LOG_ERR, "sprintaddr:getnameinfo(NUM): %s\n", gai_strerror(res)); + strcpy(host, "?"); + strcpy(serv, "?"); + } } snprintf(buf, size, "%s:%s", host, serv); @@ -436,18 +474,16 @@ void resolve_name(struct addrinfo **out, char* fullname) } } -/* Log to syslog, and to stderr if foreground */ +/* Log to syslog or stderr if foreground */ void log_message(int type, char* msg, ...) { va_list ap; - va_start(ap, msg); - vsyslog(type, msg, ap); - va_end(ap); - va_start(ap, msg); if (foreground) vfprintf(stderr, msg, ap); + else + vsyslog(type, msg, ap); va_end(ap); } diff --git a/scripts/etc.default.sslh b/scripts/etc.default.sslh index 23339aa..50894b9 100755 --- a/scripts/etc.default.sslh +++ b/scripts/etc.default.sslh @@ -1,3 +1,5 @@ LISTEN=ifname:443 SSH=localhost:22 SSL=localhost:443 +USER=nobody +PID=/var/run/sslh.pid diff --git a/scripts/etc.init.d.sslh b/scripts/etc.init.d.sslh index bcc9485..a8484c9 100755 --- a/scripts/etc.init.d.sslh +++ b/scripts/etc.init.d.sslh @@ -13,11 +13,6 @@ facility=user.info # /etc/init.d/sslh: start and stop the sslh proxy daemon -# Defaults -- can be overridden in /etc/default/sslh -LISTEN=thelonious:443 -SSH=localhost:22 -SSL=localhost:443 - if test -f /etc/default/sslh; then . /etc/default/sslh fi @@ -30,7 +25,7 @@ DAEMON=$PREFIX/sbin/sslh start() { echo "Start services: sslh" - $DAEMON --user nobody --listen ${LISTEN} --ssh ${SSH} --ssl ${SSL} + $DAEMON --user ${USER} --pidfile ${PID} --listen ${LISTEN} --ssh ${SSH} --ssl ${SSL} logger -t ${tag} -p ${facility} -i 'Started sslh' } diff --git a/scripts/etc.rc.d.init.d.sslh.centos b/scripts/etc.rc.d.init.d.sslh.centos index 2d19a1d..f7da6ef 100755 --- a/scripts/etc.rc.d.init.d.sslh.centos +++ b/scripts/etc.rc.d.init.d.sslh.centos @@ -20,7 +20,7 @@ SSLH="/usr/local/sbin/sslh" PIDFILE="/var/run/sslh" -OPTIONS="-p 0.0.0.0:8443 --ssl 127.0.0.1:443 --ssh 127.0.0.1:22" +OPTIONS="--user nobody --pidfile $PIDFILE -p 0.0.0.0:8443 --ssl 127.0.0.1:443 --ssh 127.0.0.1:22" if [ -f /etc/sysconfig/sslh ]; then . /etc/sysconfig/sslh diff --git a/sslh-fork.c b/sslh-fork.c index d46743f..e4bd69a 100644 --- a/sslh-fork.c +++ b/sslh-fork.c @@ -138,6 +138,7 @@ void main_loop(int listen_sockets[], int num_addr_listen) int in_socket, i, res; struct sigaction action; + listener_pid_number = num_addr_listen; listener_pid = malloc(listener_pid_number * sizeof(listener_pid[0])); /* Start one process for each listening address */ @@ -170,7 +171,6 @@ void main_loop(int listen_sockets[], int num_addr_listen) res = sigaction(SIGTERM, &action, NULL); CHECK_RES_DIE(res, "sigaction"); - listener_pid_number = num_addr_listen; wait(NULL); } diff --git a/sslh-main.c b/sslh-main.c index c8febc2..3d4d5b0 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -154,8 +154,8 @@ int main(int argc, char *argv[]) int *listen_sockets; /* Init defaults */ - pid_file = "/var/run/sslh.pid"; - user_name = "nobody"; + pid_file = NULL; + user_name = NULL; foreground = 0; parse_cmdline(argc, argv); @@ -172,20 +172,23 @@ int main(int argc, char *argv[]) num_addr_listen = start_listen_sockets(&listen_sockets, addr_listen); - if (!foreground) + if (!foreground) { if (fork() > 0) exit(0); /* Detach */ + /* New session -- become group leader */ + if (getuid() == 0) { + res = setsid(); + CHECK_RES_DIE(res, "setsid: already process leader"); + } + } + setup_signals(); - drop_privileges(user_name); + if (user_name) + drop_privileges(user_name); - /* New session -- become group leader */ - if (getuid() == 0) { - res = setsid(); - CHECK_RES_DIE(res, "setsid: already process leader"); - } - - write_pid_file(pid_file); + if (pid_file) + write_pid_file(pid_file); /* Open syslog connection */ setup_syslog(argv[0]); diff --git a/sslh.pod b/sslh.pod index d2fadde..07065b8 100644 --- a/sslh.pod +++ b/sslh.pod @@ -6,15 +6,15 @@ =head1 SYNOPSIS -sslh [ B<-t> I ] [B<-p> I [B<-p> I ...] [B<--ssl> I] [B<--ssh> I] [B<--openvpn> I] [B<-u> I] [B<-P> I] [-v] [-i] [-V] [-f] [-n] +sslh [ B<-t> I ] [B<-p> I [B<-p> I ...] [B<--ssl> I] [B<--ssh> I] [B<--openvpn> I] [B<--http> I] [B<-u> I] [B<-P> I] [-v] [-i] [-V] [-f] [-n] =head1 DESCRIPTION -B accepts HTTPS, SSH, OpenVPN, tinc and XMPP connections -on the same port. This makes it possible to connect to any -of these servers on port 443 (e.g. from inside a corporate -firewall, which almost never block port 443) while still -serving HTTPS on that port. +B accepts HTTP, HTTPS, SSH, OpenVPN, tinc and XMPP +connections on the same port. This makes it possible to +connect to any of these servers on port 443 (e.g. from +inside a corporate firewall, which almost never block port +443) while still serving HTTPS on that port. The idea is to have B listen to the external 443 port, @@ -123,14 +123,12 @@ Prints B version. =item B<-u> I, B<--user> I -Requires to run under the specified username. Defaults to -I (which is not perfect -- ideally B should -run under its own UID). +Requires to run under the specified username. =item B<-P> I, B<--pid-file> I -Specifies the file in which to write the PID of the main -server. Defaults to I. +Specifies a file in which to write the PID of the main +server. =item B<-i>, B<--inetd>