v1.6: 25APR2009

Added -V, version option.
        Install target directory configurable in Makefile
        Changed syslog prefix in auth.log to "sslh[%pid]"
        Man page
        new 'make install' and 'make install-debian' targets
        PID file now specified using -P command line option
        Actually fixed zombie generation (the v1.5 patch got
        lost, doh!)
This commit is contained in:
Yves Rutschle 2013-07-10 23:10:43 +02:00
parent b965d735b8
commit 0658982705
6 changed files with 239 additions and 41 deletions

View File

@ -1,23 +1,49 @@
# Configuration
VERSION="v1.6i"
USELIBWRAP=1 # Use libwrap?
PREFIX=/usr/local
MAN=sslh.8.gz # man page name
# End of configuration -- the rest should take care of
# itself
CC = gcc
CFLAGS=-Wall
#LIBS=-lnet
LIBS=
ifneq ($(strip $(USELIBWRAP)),)
LIBS:=$(LIBS) -lwrap
CFLAGS=-DLIBWRAP
CFLAGS:=$(CFLAGS) -DLIBWRAP
endif
all:
$(CC) $(CFLAGS) -o sslh sslh.c $(LIBS)
all: sslh $(MAN)
sslh: sslh.c Makefile
$(CC) $(CFLAGS) -D'VERSION=$(VERSION)' -o sslh sslh.c $(LIBS)
strip sslh
$(MAN): sslh.pod Makefile
pod2man --section=8 --release=$(VERSION) --center=" " sslh.pod | gzip -9 - > $(MAN)
# generic install: install binary and man page
install: sslh $(MAN)
install -D sslh $(PREFIX)/sbin/sslh
install -D -m 0644 $(MAN) $(PREFIX)/share/man/man8/$(MAN)
# "extended" install for Debian: install startup script
install-debian: install sslh $(MAN)
sed -e "s+^PREFIX=+PREFIX=$(PREFIX)+" scripts/etc.init.d.sslh > /etc/init.d/sslh
chmod 755 /etc/init.d/sslh
cp scripts/etc.default.sslh /etc/default/sslh
update-rc.d sslh defaults
uninstall:
rm -f $(PREFIX)/sbin/sslh $(PREFIX)/share/man/man8/$(MAN) /etc/init.d/sslh /etc/default/sslh
update-rc.d sslh remove
clean:
rm -f sslh $(MAN)

44
README
View File

@ -1,10 +1,20 @@
sslh -- A ssl/ssh multiplexer.
===== 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.
==== Compile and install ====
If you're lucky, the Makefile will work for you:
make install
(see below for configuration hints)
Otherwise:
Compilation instructions:
@ -29,18 +39,29 @@ cp sslh /usr/local/sbin
cp scripts/etc.init.d.sslh /etc/init.d/sslh
cp scripts/etc.default.sslh /etc/default/sslh
and probably create links in /etc/rc<x>.d so that the server
start automatically at boot-up, e.g. under Debian:
update-rc.d sslh defaults
==== Configuration ====
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.
$LISTEN, and bind httpd to localhost:443 (instead of all
binding to all interfaces): 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.
==== Libwrap support ====
Sslh can optionnaly perform libwrap checks for the sshd
service: because the connection to sshd will be coming
@ -51,6 +72,17 @@ Comments? questions? sslh@rutschle.net
HISTORY
v1.6: 25APR2009
Added -V, version option.
Install target directory configurable in Makefile
Changed syslog prefix in auth.log to "sslh[%pid]"
Man page
new 'make install' and 'make install-debian' targets
PID file now specified using -P command line option
Actually fixed zombie generation (the v1.5 patch got
lost, doh!)
v1.5: 10DEC2008
Fixed zombie generation.
Added support scripts (), Makefile.

View File

@ -1,4 +1,3 @@
PIDFILE=/var/run/sslh.pid
LISTEN=ifname:443
SSH=localhost:22
SSL=localhost:443

View File

@ -14,17 +14,18 @@ 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
# The prefix is normally filled by make install. If
# installing by hand, fill it in yourself!
PREFIX=
DAEMON=$PREFIX/sbin/sslh
start()
{

68
sslh.c
View File

@ -20,8 +20,7 @@
*/
#define VERSION "1.5"
#define _GNU_SOURCE
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
@ -36,6 +35,7 @@
#include <netdb.h>
#include <pwd.h>
#include <syslog.h>
#include <libgen.h>
#ifdef LIBWRAP
#include <tcpd.h>
@ -50,15 +50,16 @@ if (res == -1) { \
}
#define USAGE_STRING \
"sslh v" VERSION "\n" \
"sslh " VERSION "\n" \
"usage:\n" \
"\texport PIDFILE=/var/run/sslhc.pid\n" \
"\tsslh [-t <timeout>] -u <username> -p [listenaddr:]<listenport> \n" \
"\t\t-s [sshhost:]port -l [sslhost:]port [-v]\n\n" \
"\t\t-s [sshhost:]port -l [sslhost:]port [-P pidfile] [-v] [-V]\n\n" \
"-v: verbose\n" \
"-V: version\n" \
"-p: address and port to listen on. default: 0.0.0.0:443\n" \
"-s: SSH address: where to connect an SSH connection. default: localhost:22\n" \
"-l: SSL address: where to connect an SSL connection.\n" \
"-P: PID file. Default: /var/run/sslh.pid\n" \
""
int verbose = 0; /* That's really quite global */
@ -188,7 +189,7 @@ void resolve_name(struct sockaddr *sock, char* fullname) {
res = getaddrinfo(host, serv, &hint, &addr);
if (res) {
fprintf(stderr, "%s\n", gai_strerror(res));
fprintf(stderr, "%s `%s'\n", gai_strerror(res), fullname);
if (res == EAI_SERVICE)
fprintf(stderr, "(Check you have specified all ports)\n");
exit(1);
@ -306,25 +307,31 @@ void start_shoveler(int in_socket)
exit(0);
}
/* SIGCHLD handling:
* we need to reap our children
*/
void child_handler(int signo)
{
signal(SIGCHLD, &child_handler);
wait(NULL);
}
void setup_signals(void)
{
void* res;
int res;
struct sigaction action;
res = signal(SIGCHLD, &child_handler);
if (res == SIG_ERR) {
perror("signal");
exit(1);
}
/* Request no SIGCHLD is sent upon termination of
* the children */
memset(&action, 0, sizeof(action));
action.sa_handler = NULL;
action.sa_flags = SA_NOCLDWAIT;
res = sigaction(SIGCHLD, &action, NULL);
CHECK_RES_DIE(res, "sigaction");
}
/* Open syslog connection with appropriate banner;
* banner is made up of basename(bin_name)+"[pid]" */
void setup_syslog(char* bin_name) {
char *name1, *name2;
name1 = strdup(bin_name);
asprintf(&name2, "%s[%d]", basename(name1), getpid());
openlog(name2, LOG_CONS, LOG_AUTH);
free(name1);
/* Don't free name2, as openlog(3) uses it (at least in glibc) */
}
/* We don't want to run as root -- drop priviledges if required */
void drop_privileges(char* user_name)
@ -345,14 +352,10 @@ void drop_privileges(char* user_name)
}
/* Writes my PID if $PIDFILE is defined */
void write_pid_file(void)
void write_pid_file(char* pidfile)
{
char *pidfile = getenv("PIDFILE");
FILE *f;
if (!pidfile)
return;
f = fopen(pidfile, "w");
if (!f) {
perror(pidfile);
@ -391,12 +394,13 @@ int main(int argc, char *argv[])
char listen_str[] = "0.0.0.0:443";
char ssl_str[] = "localhost:442";
char ssh_str[] = "localhost:22";
char *pid_file = "/var/run/sslh.pid";
resolve_name(&addr_listen, listen_str);
resolve_name(&addr_ssl, ssl_str);
resolve_name(&addr_ssh, ssh_str);
while ((c = getopt(argc, argv, "t:l:s:p:vu:")) != EOF) {
while ((c = getopt(argc, argv, "t:l:s:p:P:vVu:")) != EOF) {
switch (c) {
case 't':
@ -419,10 +423,18 @@ int main(int argc, char *argv[])
verbose += 1;
break;
case 'V':
printf("sslh %s\n", VERSION);
exit(0);
case 'u':
user_name = optarg;
break;
case 'P':
pid_file = optarg;
break;
default:
fprintf(stderr, USAGE_STRING);
exit(2);
@ -438,7 +450,7 @@ int main(int argc, char *argv[])
if (fork() > 0) exit(0); /* Detach */
write_pid_file();
write_pid_file(pid_file);
drop_privileges(user_name);
@ -447,7 +459,7 @@ int main(int argc, char *argv[])
CHECK_RES_DIE(res, "setsid: already process leader");
/* Open syslog connection */
openlog(argv[0], LOG_CONS, LOG_AUTH);
setup_syslog(argv[0]);
/* Main server loop: accept connections, find what they are, fork shovelers */
while (1)

128
sslh.pod Normal file
View File

@ -0,0 +1,128 @@
# I'm just not gonna write troff :-)
=head1 NAME
sslh - ssl/ssh multiplexer
=head1 SYNOPSIS
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<-u> I<username>] [B<-P> I<pidfile>] [-v] [-V]
=head1 DESCRIPTION
B<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,
which almost never block port 443) while still serving HTTPS
on that port.
The idea is to have B<sslh> listen to the external 443 port,
accept the incoming connections, work out what type of
connection it is, and then fordward to the appropriate
server.
=head2 Protocol detection
The protocol detection is made based on a small difference
between SSL and SSH: an SSL client connecting to a server
speaks first, whereas an SSH client expects the SSH server
to speak first (announcing itself with a banner). B<sslh>
waits for some time for the incoming connection to send data.
If it does before the timeout occurs, it is supposed to be
an SSL connection. Otherwise, it is supposed to be an SSH
connection.
=head2 Libwrap support
One drawback of B<sslh> is that the B<ssh> and B<httpd>
servers do not see the original IP address of the client
anymore, as the connection is forwarded through B<sslh>.
B<sslh> provides enough logging to circumvent that problem.
However it is common to limit access to B<ssh> using
B<libwrap> or B<tcpd>. For this reason, B<sslh> can be
compiled to check SSH accesses against SSH access lists as
defined in F</etc/hosts.allow> and F</etc/hosts.deny>.
=head1 OPTIONS
=over 4
=item B<-t> I<num>
Timeout before a connection is considered to be SSH. Default
is 2s.
=item B<-p> I<listening address>
Interface and port on which to listen, e.g. I<foobar:443>,
where I<foobar> is the name of an interface (typically the
IP address on which the Internet connection ends up).
Defaults to I<0.0.0.0:443> (listen to port 443 on all
available interfaces).
=item B<-l> I<target address for SSL>
Interface and port on which to forward SSL connection,
typically I<localhost:443>.
Defaults to I<localhost:442> (this assumes you would
configure your B<httpd> process to listen to port 443).
Note that you can set B<sslh> to listen on I<ext_ip:443> and
B<httpd> to listen on I<localhost:443>: this allows clients
inside your network to just connect directly to B<httpd>.
=item B<-s> I<target address for SSH>
Interface and port on which to forward SSH connection,
defaults to I<localhost:22>.
=item B<-v>
Increase verboseness.
=item B<-V>
Prints B<sslh> version.
=item B<-u> I<username>
Requires to run under the specified username. Defaults to
I<nobody> (which is not perfect -- ideally B<sslh> should
run under its own UID).
=item B<-P> I<pidfile>
Specifies the file in which to write the PID of the main
server. Defaults to I</var/run/sslh.pid>.
=back
=head1 FILES
=over 4
=item F</etc/init.d/sslh>
Start-up script. The standard actions B<start>, B<stop> and
B<restart> are supported.
=item F</etc/default/sslh>
Server configuration. These are environement variables
loaded by the start-up script and passed to B<sslh> as
command-line arguments. Refer to the OPTIONS section for a
detailed explanation of the variables used by B<sslh>.
=back
=head1 SEE ALSO
Last version available from
L<http://www.rutschle.net/tech/sslh>, and can be tracked
from L<http://freshmeat.net/projects/sslh/>.
=head1 AUTHOR
Written by Yves Rutschle