From b965d735b8cede5dfc93947da5c59e562aceb559 Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Wed, 10 Jul 2013 23:09:40 +0200 Subject: [PATCH] v1.5: 10DEC2008 Fixed zombie generation. Added support scripts (), Makefile. Changed all 'connexions' to 'connections' to please pesky users. Damn users. --- Makefile | 23 +++++++++++ README | 83 +++++++++++++++++++++++++++++++++++++ scripts/etc.default.sslh | 4 ++ scripts/etc.init.d.sslh | 62 ++++++++++++++++++++++++++++ sslh.c | 88 +++++++++++++++++++++------------------- 5 files changed, 218 insertions(+), 42 deletions(-) create mode 100644 Makefile create mode 100644 README create mode 100755 scripts/etc.default.sslh create mode 100755 scripts/etc.init.d.sslh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..33aca4b --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +# Configuration + +USELIBWRAP=1 # Use libwrap? + + +# End of configuration -- the rest should take care of +# itself + +CC = gcc + +#LIBS=-lnet +LIBS= + +ifneq ($(strip $(USELIBWRAP)),) + LIBS:=$(LIBS) -lwrap + CFLAGS=-DLIBWRAP +endif + +all: + $(CC) $(CFLAGS) -o sslh sslh.c $(LIBS) + strip sslh + + diff --git a/README b/README new file mode 100644 index 0000000..9954f86 --- /dev/null +++ b/README @@ -0,0 +1,83 @@ +sslh -- A ssl/ssh multiplexer. + +sslh lets one accept both HTTPS and SSH connections on the +same port. It makes it possible to connect to an SSH server +on port 443 (e.g. from inside a corporate firewall) while +still serving HTTPS on that port. + + +Compilation instructions: + +Solaris: + cc -o sslh sslh.c -lresolv -lsocket -lnsl + +LynxOS: + gcc -o tcproxy tcproxy.c -lnetinet + +Linux: + cc -o sslh sslh.c -lnet +or: + cc -o sslh sslh.c + +To compile with libwrap support: + cc -o sslh -DLIBWRAP sslh.c -lwrap + +To install: + +make +cp sslh /usr/local/sbin +cp scripts/etc.init.d.sslh /etc/init.d/sslh +cp scripts/etc.default.sslh /etc/default/sslh + +You can edit settings in /etc/default/sslh: + +PIDFILE=/var/run/sslh.pid +LISTEN=ifname:443 +SSH=localhost:22 +SSL=localhost:443 + +A good scheme is to use the external name of the machine in +$LISTEN, and bind httpd to localhost:443: that way, https +connections coming from inside your network don't need to go +through sslh, and sslh is only there as a frontal for +connections coming from the internet. + +Sslh can optionnaly perform libwrap checks for the sshd +service: because the connection to sshd will be coming +locally from sslh, sshd cannot determine the IP of the +client. + +Comments? questions? sslh@rutschle.net + +HISTORY + +v1.5: 10DEC2008 + Fixed zombie generation. + Added support scripts (), Makefile. + Changed all 'connexions' to 'connections' to please + pesky users. Damn users. + +v1.4: 13JUL2008 + Added libwrap support for ssh service (Christian Weinberger) + Only SSH is libwraped, not SSL. + +v1.3: 14MAY2008 + Added parsing for local interface to listen on + Changed default SSL connection to port 442 (443 doesn't make + sense as a default as we're already listening on 443) + Syslog incoming connections + +v1.2: 12MAY2008 + Fixed compilation warning for AMD64 (Thx Daniel Lange) + +v1.1: 21MAY2007 + Making sslhc more like a real daemon: + * If $PIDFILE is defined, write first PID to it upon startup + * Fork at startup (detach from terminal) + (thanks to http://www.enderunix.org/docs/eng/daemon.php -- good checklist) + * Less memory usage (?) + +v1.0: + * Basic functionality: privilege dropping, target hostnames and ports + configurable. + diff --git a/scripts/etc.default.sslh b/scripts/etc.default.sslh new file mode 100755 index 0000000..4fb2880 --- /dev/null +++ b/scripts/etc.default.sslh @@ -0,0 +1,4 @@ +PIDFILE=/var/run/sslh.pid +LISTEN=ifname:443 +SSH=localhost:22 +SSL=localhost:443 diff --git a/scripts/etc.init.d.sslh b/scripts/etc.init.d.sslh new file mode 100755 index 0000000..f08782f --- /dev/null +++ b/scripts/etc.init.d.sslh @@ -0,0 +1,62 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: sslh +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +# Short-Description: sslh proxy ssl & ssh connections +### END INIT INFO + +set -e +tag=sslh +facility=user.info + +# /etc/init.d/sslh: start and stop the sslh proxy daemon + +# Defaults -- can be overridden in /etc/default/sslh +PIDFILE=/var/run/sslh.pid +LISTEN=thelonious:443 +SSH=localhost:22 +SSL=localhost:443 + +if test -f /etc/default/sslh; then + . /etc/default/sslh + export PIDFILE=${PIDFILE} +fi + +DAEMON=/usr/local/sbin/sslh + +start() +{ + echo "Start services: sslh" + $DAEMON -u nobody -p ${LISTEN} -s ${SSH} -l ${SSL} + logger -t ${tag} -p ${facility} -i 'Started sslh' +} + +stop() +{ + echo "Stop services: sslh" + killall $DAEMON + rm ${PIDFILE} + logger -t ${tag} -p ${facility} -i 'Stopped sslh' +} + + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + sleep 5 + start + ;; + *) + echo "Usage: /etc/init.d/sslh {start|stop|restart}" >&2 + ;; +esac + +exit 0 diff --git a/sslh.c b/sslh.c index 8e51f00..b0c6674 100644 --- a/sslh.c +++ b/sslh.c @@ -18,44 +18,9 @@ # The full text for the General Public License is here: # http://www.gnu.org/licenses/gpl.html -Comments? questions? sslh@rutschle.net - -Compilation instructions: - -Solaris: - cc -o sslh sslh.c -lresolv -lsocket -lnsl - -LynxOS: - gcc -o tcproxy tcproxy.c -lnetinet - -Linux: - cc -o sslh sslh.c -lnet - -HISTORY - -v1.3: 14MAY2008 - Added parsing for local interface to listen on - Changed default SSL connexion to port 442 (443 doesn't make - sense as a default as we're already listening on 443) - Syslog incoming connexions - -v1.2: 12MAY2008 - Fixed compilation warning for AMD64 (Thx Daniel Lange) - -v1.1: 21MAY2007 - Making sslhc more like a real daemon: - * If $PIDFILE is defined, write first PID to it upon startup - * Fork at startup (detach from terminal) - (thanks to http://www.enderunix.org/docs/eng/daemon.php -- good checklist) - * Less memory usage (?) - -v1.0: - * Basic functionality: privilege dropping, target hostnames and ports - configurable. - */ -#define VERSION "1.3" +#define VERSION "1.5" #include #include @@ -72,6 +37,12 @@ v1.0: #include #include +#ifdef LIBWRAP +#include +int allow_severity =0, deny_severity = 0; +#endif + + #define CHECK_RES_DIE(res, str) \ if (res == -1) { \ perror(str); \ @@ -86,8 +57,8 @@ if (res == -1) { \ "\t\t-s [sshhost:]port -l [sslhost:]port [-v]\n\n" \ "-v: verbose\n" \ "-p: address and port to listen on. default: 0.0.0.0:443\n" \ -"-s: SSH address: where to connect an SSH connexion. default: localhost:22\n" \ -"-l: SSL address: where to connect an SSL connexion.\n" \ +"-s: SSH address: where to connect an SSH connection. default: localhost:22\n" \ +"-l: SSL address: where to connect an SSL connection.\n" \ "" int verbose = 0; /* That's really quite global */ @@ -227,7 +198,7 @@ void resolve_name(struct sockaddr *sock, char* fullname) { } /* syslogs who connected to where */ -void log_connexion(int socket, char* target) +void log_connection(int socket, char* target) { struct sockaddr peeraddr; socklen_t size = sizeof(peeraddr); @@ -237,7 +208,7 @@ void log_connexion(int socket, char* target) res = getpeername(socket, &peeraddr, &size); CHECK_RES_DIE(res, "getpeername"); - syslog(LOG_INFO, "connexion from %s forwarded to %s\n", + syslog(LOG_INFO, "connection from %s forwarded to %s\n", sprintaddr(buf, sizeof(buf), &peeraddr), target); } @@ -251,6 +222,36 @@ int timeout = 2; struct sockaddr addr_listen; struct sockaddr addr_ssl, addr_ssh; +/* libwrap (tcpd): check the ssh connection is legal. This is necessary because + * the actual sshd will only see a connection coming from localhost and can't + * apply the rules itself. + */ +void check_access_rights(int in_socket) +{ +#ifdef LIBWRAP + struct sockaddr peeraddr; + socklen_t size = sizeof(peeraddr); + char addr_str[1024]; + struct hostent *host; + struct in_addr addr; + int res; + + res = getpeername(in_socket, &peeraddr, &size); + CHECK_RES_DIE(res, "getpeername"); + inet_ntop(AF_INET, &((struct sockaddr_in*)&peeraddr)->sin_addr, addr_str, sizeof(addr_str)); + + addr.s_addr = inet_addr(addr_str); + host = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); + + if (!hosts_ctl("sshd", (host ? host->h_name : STRING_UNKNOWN), addr_str, STRING_UNKNOWN)) { + if (verbose) + fprintf(stderr, "access denied\n"); + log_connection(in_socket, "access denied"); + close(in_socket); + exit(0); + } +#endif +} /* Child process that finds out what to connect to and proxies */ @@ -280,9 +281,12 @@ void start_shoveler(int in_socket) /* The client hasn't written anything and we timed out: connect to SSH */ saddr = &addr_ssh; target = "SSH"; + + /* do hosts_access check if built with libwrap support */ + check_access_rights(in_socket); } - log_connexion(in_socket, target); + log_connection(in_socket, target); /* Connect the target socket */ out_socket = socket(AF_INET, SOCK_STREAM, 0); @@ -442,7 +446,7 @@ int main(int argc, char *argv[]) res = setsid(); CHECK_RES_DIE(res, "setsid: already process leader"); - /* Open syslog connexion */ + /* Open syslog connection */ openlog(argv[0], LOG_CONS, LOG_AUTH); /* Main server loop: accept connections, find what they are, fork shovelers */