mirror of
https://github.com/moparisthebest/sslh
synced 2024-11-12 04:05:05 -05:00
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.
This commit is contained in:
parent
80f76c6fc5
commit
a9c9941988
29
ChangeLog
29
ChangeLog
@ -1,4 +1,31 @@
|
|||||||
v1.8:
|
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.
|
||||||
|
|
||||||
|
v1.8: 15JUL2011
|
||||||
Changed log format to make it possible to link
|
Changed log format to make it possible to link
|
||||||
connections to subsequent logs from other services.
|
connections to subsequent logs from other services.
|
||||||
|
|
||||||
|
6
Makefile
6
Makefile
@ -1,6 +1,6 @@
|
|||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
VERSION="v1.8"
|
VERSION="v1.9"
|
||||||
USELIBWRAP= # Use libwrap?
|
USELIBWRAP= # Use libwrap?
|
||||||
PREFIX=/usr/local
|
PREFIX=/usr/local
|
||||||
|
|
||||||
@ -29,11 +29,11 @@ all: sslh $(MAN)
|
|||||||
|
|
||||||
sslh: $(OBJS) sslh-fork sslh-select
|
sslh: $(OBJS) sslh-fork sslh-select
|
||||||
|
|
||||||
sslh-fork: $(OBJS) sslh-fork.o Makefile
|
sslh-fork: $(OBJS) sslh-fork.o Makefile common.h
|
||||||
$(CC) $(CFLAGS) -D'VERSION=$(VERSION)' -o sslh-fork sslh-fork.o $(OBJS) $(LIBS)
|
$(CC) $(CFLAGS) -D'VERSION=$(VERSION)' -o sslh-fork sslh-fork.o $(OBJS) $(LIBS)
|
||||||
strip sslh-fork
|
strip sslh-fork
|
||||||
|
|
||||||
sslh-select: $(OBJS) sslh-select.o Makefile
|
sslh-select: $(OBJS) sslh-select.o Makefile common.h
|
||||||
$(CC) $(CFLAGS) -D'VERSION=$(VERSION)' -o sslh-select sslh-select.o $(OBJS) $(LIBS)
|
$(CC) $(CFLAGS) -D'VERSION=$(VERSION)' -o sslh-select sslh-select.o $(OBJS) $(LIBS)
|
||||||
strip sslh-select
|
strip sslh-select
|
||||||
|
|
||||||
|
8
README
8
README
@ -104,22 +104,22 @@ In that case, you end up with something like this:
|
|||||||
|
|
||||||
ssh -> proxytunnel -e --------ssh/ssl------> stunnel ---ssh---> sslh --> sshd
|
ssh -> proxytunnel -e --------ssh/ssl------> stunnel ---ssh---> sslh --> sshd
|
||||||
|
|
||||||
navigateur --------http/ssl------> stunnel ---http---> sslh --> http:80
|
Web browser --------http/ssl------> stunnel ---http---> sslh --> http:80
|
||||||
|
|
||||||
Configuration goes like this:
|
Configuration goes like this:
|
||||||
|
|
||||||
On the server side, using stunnel3:
|
On the server side, using stunnel3:
|
||||||
stunnel -f -p mycert.pem -d thelonious:443 -l /usr/local/sbin/sslh -- sslh -i -l localhost:80 -s localhost:22
|
stunnel -f -p mycert.pem -d thelonious:443 -l /usr/local/sbin/sslh -- sslh -i --ssl localhost:80 --ssh localhost:22
|
||||||
|
|
||||||
stunnel options: -f for foreground/debugging, -p specifies
|
stunnel options: -f for foreground/debugging, -p specifies
|
||||||
the key + certificate, -d specifies which interface and port
|
the key + certificate, -d specifies which interface and port
|
||||||
we're listening to for incoming connexions, -l summons sslh
|
we're listening to for incoming connexions, -l summons sslh
|
||||||
in inetd mode.
|
in inetd mode.
|
||||||
|
|
||||||
sslh options: -i for inetd mode, -l to forward SSL
|
sslh options: -i for inetd mode, --ssl to forward SSL
|
||||||
connexions (in fact normal HTTP at that stage) to port 80,
|
connexions (in fact normal HTTP at that stage) to port 80,
|
||||||
and SSH connexions to port 22. This works because sslh
|
and SSH connexions to port 22. This works because sslh
|
||||||
considers that anything that is not SSH is SSL.
|
considers that any protocol it doesn't recognise is SSL.
|
||||||
|
|
||||||
==== IP_TPROXY support ====
|
==== IP_TPROXY support ====
|
||||||
|
|
||||||
|
296
common.c
296
common.c
@ -21,6 +21,7 @@
|
|||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
@ -32,31 +33,34 @@
|
|||||||
|
|
||||||
int is_ssh_protocol(const char *p, int len);
|
int is_ssh_protocol(const char *p, int len);
|
||||||
int is_openvpn_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_true(const char *p, int len) { return 1; }
|
int is_true(const char *p, int len) { return 1; }
|
||||||
|
|
||||||
struct proto protocols[] = {
|
struct proto protocols[] = {
|
||||||
/* affected description service saddr probe */
|
/* affected description service saddr probe */
|
||||||
{ 0, "SSH", "sshd", {0}, is_ssh_protocol },
|
{ 0, "ssh", "sshd", {0}, is_ssh_protocol },
|
||||||
{ 0, "OpenVPN", NULL, {0}, is_openvpn_protocol },
|
{ 0, "openvpn", NULL, {0}, is_openvpn_protocol },
|
||||||
|
{ 0, "tinc", NULL, {0}, is_tinc_protocol },
|
||||||
/* probe for SSL always successes: it's the default, and must be tried last
|
/* probe for SSL always successes: it's the default, and must be tried last
|
||||||
**/
|
**/
|
||||||
{ 0, "SSL", NULL, {0}, is_true }
|
{ 0, "ssl", NULL, {0}, is_true }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const char* USAGE_STRING =
|
const char* USAGE_STRING =
|
||||||
"sslh " VERSION "\n" \
|
"sslh " VERSION "\n" \
|
||||||
"usage:\n" \
|
"usage:\n" \
|
||||||
"\tsslh [-v] [-i] [-V] [-f]"
|
"\tsslh [-v] [-i] [-V] [-f]\n"
|
||||||
"[-t <timeout>] -u <username> -p [listenaddr:]<listenport> \n" \
|
"\t[-t <timeout>] [-P <pidfile>] -u <username> -p <add> [-p <addr> ...] \n" \
|
||||||
"\t\t-s [sshhost:]port -l [sslhost:]port [-P pidfile]\n\n" \
|
"\t[--ssh <addr>] [--ssl <addr>] [--openvpn <addr>] [--tinc <addr>]\n\n" \
|
||||||
"-v: verbose\n" \
|
"-v: verbose\n" \
|
||||||
"-V: version\n" \
|
"-V: version\n" \
|
||||||
"-f: foreground\n" \
|
"-f: foreground\n" \
|
||||||
"-p: address and port to listen on. default: 0.0.0.0:443\n" \
|
"-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" \
|
||||||
"-s: SSH address: where to connect an SSH connection. default: localhost:22\n" \
|
"--ssh: SSH address: where to connect an SSH connection.\n" \
|
||||||
"-l: SSL address: where to connect an SSL connection.\n" \
|
"--ssl: SSL address: where to connect an SSL connection.\n" \
|
||||||
"-o: OpenVPN address: where to connect an OpenVPN connection.\n" \
|
"--openvpn: OpenVPN address: where to connect an OpenVPN connection.\n" \
|
||||||
|
"--tinc: tinc address: where to connect a tinc connection.\n" \
|
||||||
"-P: PID file. Default: /var/run/sslh.pid.\n" \
|
"-P: PID file. Default: /var/run/sslh.pid.\n" \
|
||||||
"-i: Run as a inetd service.\n" \
|
"-i: Run as a inetd service.\n" \
|
||||||
"";
|
"";
|
||||||
@ -71,38 +75,59 @@ int verbose = 0;
|
|||||||
int probing_timeout = 2;
|
int probing_timeout = 2;
|
||||||
int inetd = 0;
|
int inetd = 0;
|
||||||
int foreground = 0;
|
int foreground = 0;
|
||||||
struct sockaddr addr_listen;
|
int numeric = 0;
|
||||||
char *user_name, *pid_file;
|
char *user_name, *pid_file;
|
||||||
|
|
||||||
|
struct sockaddr_storage *addr_listen = NULL; /* what addresses do we listen to? */
|
||||||
|
int num_addr_listen = 0; /* How many addresses do we listen to? */
|
||||||
|
|
||||||
#ifdef LIBWRAP
|
#ifdef LIBWRAP
|
||||||
#include <tcpd.h>
|
#include <tcpd.h>
|
||||||
int allow_severity =0, deny_severity = 0;
|
int allow_severity =0, deny_severity = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* check result and die, printing the offending address and error */
|
||||||
|
void check_res_dumpdie(int res, struct sockaddr_storage *sock, char* syscall)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
/* Starts a listening socket on specified address.
|
if (res == -1) {
|
||||||
|
fprintf(stderr, "%s:%s: %s\n",
|
||||||
|
sprintaddr(buf, sizeof(buf), sock),
|
||||||
|
syscall,
|
||||||
|
strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Starts listening sockets on specified addresses.
|
||||||
|
* IN: addr[], num_addr
|
||||||
|
* OUT: sockfd[]
|
||||||
|
* Bound file descriptors are returned in alread-allocated *sockfd pointer
|
||||||
Returns file descriptor
|
Returns file descriptor
|
||||||
*/
|
*/
|
||||||
int start_listen_socket(struct sockaddr *addr)
|
void start_listen_sockets(int sockfd[], struct sockaddr_storage addr[], int num_addr)
|
||||||
{
|
{
|
||||||
struct sockaddr_in *saddr = (struct sockaddr_in*)addr;
|
struct sockaddr_storage *saddr;
|
||||||
int sockfd, res, reuse;
|
int i, res, reuse;
|
||||||
|
|
||||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
for (i = 0; i < num_addr; i++) {
|
||||||
CHECK_RES_DIE(sockfd, "socket");
|
saddr = &addr[i];
|
||||||
|
|
||||||
reuse = 1;
|
sockfd[i] = socket(saddr->ss_family, SOCK_STREAM, 0);
|
||||||
res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
|
check_res_dumpdie(sockfd[i], saddr, "socket");
|
||||||
CHECK_RES_DIE(res, "setsockopt");
|
|
||||||
|
|
||||||
res = bind (sockfd, (struct sockaddr*)saddr, sizeof(*saddr));
|
reuse = 1;
|
||||||
CHECK_RES_DIE(res, "bind");
|
res = setsockopt(sockfd[i], SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
|
||||||
|
check_res_dumpdie(res, saddr, "setsockopt");
|
||||||
|
|
||||||
res = listen (sockfd, 50);
|
res = bind (sockfd[i], (struct sockaddr*)saddr, sizeof(*saddr));
|
||||||
CHECK_RES_DIE(res, "listen");
|
check_res_dumpdie(res, saddr, "bind");
|
||||||
|
|
||||||
return sockfd;
|
res = listen (sockfd[i], 50);
|
||||||
|
check_res_dumpdie(res, saddr, "listen");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store some data to write to the queue later */
|
/* Store some data to write to the queue later */
|
||||||
@ -260,6 +285,13 @@ int is_openvpn_protocol (const char*p,int len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is the buffer the beginning of a tinc connections?
|
||||||
|
* (protocol is undocumented, but starts with "0 " in 1.0.15)
|
||||||
|
* */
|
||||||
|
int is_tinc_protocol( const char *p, int len)
|
||||||
|
{
|
||||||
|
return !strncmp(p, "0 ", len);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the beginning of data coming from the client connection and check if
|
* Read the beginning of data coming from the client connection and check if
|
||||||
@ -290,17 +322,26 @@ T_PROTO_ID probe_client_protocol(struct connection *cnx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If none worked, return the last one */
|
/* If none worked, return the first one affected (that's completely
|
||||||
return ARRAY_SIZE(protocols) - 1;
|
* arbitrary) */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(protocols); i++)
|
||||||
|
if (protocols[i].affected)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
/* At this stage... nothing is affected. This shouldn't happen as we check
|
||||||
|
* at least one target exists when we parse the commnand line */
|
||||||
|
fprintf(stderr, "FATAL: No protocol affected. This should not happen.\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns a string that prints the IP and port of the sockaddr */
|
/* returns a string that prints the IP and port of the sockaddr */
|
||||||
char* sprintaddr(char* buf, size_t size, struct sockaddr* s)
|
char* sprintaddr(char* buf, size_t size, struct sockaddr_storage* s)
|
||||||
{
|
{
|
||||||
char addr_str[1024];
|
char host[NI_MAXHOST], serv[NI_MAXSERV];
|
||||||
|
|
||||||
|
getnameinfo((struct sockaddr*)s, sizeof(*s), host, sizeof(host), serv, sizeof(serv), numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 );
|
||||||
|
snprintf(buf, size, "%s:%s", host, serv);
|
||||||
|
|
||||||
inet_ntop(AF_INET, &((struct sockaddr_in*)s)->sin_addr, addr_str, sizeof(addr_str));
|
|
||||||
snprintf(buf, size, "%s:%d", addr_str, ntohs(((struct sockaddr_in*)s)->sin_port));
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,28 +349,26 @@ char* sprintaddr(char* buf, size_t size, struct sockaddr* s)
|
|||||||
sock: socket address to which to copy the addr
|
sock: socket address to which to copy the addr
|
||||||
fullname: input string -- it gets clobbered
|
fullname: input string -- it gets clobbered
|
||||||
*/
|
*/
|
||||||
void resolve_name(struct sockaddr *sock, char* fullname)
|
void resolve_name(struct sockaddr_storage *sock, char* fullname)
|
||||||
{
|
{
|
||||||
struct addrinfo *addr, hint;
|
struct addrinfo *addr, hint;
|
||||||
char *serv, *host;
|
char *serv, *host;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
char *sep = strchr(fullname, ':');
|
char *sep = strrchr(fullname, ':');
|
||||||
|
|
||||||
if (!sep) /* No separator: parameter is just a port */
|
if (!sep) /* No separator: parameter is just a port */
|
||||||
{
|
{
|
||||||
serv = fullname;
|
|
||||||
fprintf(stderr, "names must be fully specified as hostname:port\n");
|
fprintf(stderr, "names must be fully specified as hostname:port\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
host = fullname;
|
host = fullname;
|
||||||
serv = sep+1;
|
serv = sep+1;
|
||||||
*sep = 0;
|
*sep = 0;
|
||||||
}
|
|
||||||
|
|
||||||
memset(&hint, 0, sizeof(hint));
|
memset(&hint, 0, sizeof(hint));
|
||||||
hint.ai_family = PF_INET;
|
hint.ai_family = PF_UNSPEC;
|
||||||
hint.ai_socktype = SOCK_STREAM;
|
hint.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
res = getaddrinfo(host, serv, &hint, &addr);
|
res = getaddrinfo(host, serv, &hint, &addr);
|
||||||
@ -363,19 +402,40 @@ void log_message(int type, char* msg, ...)
|
|||||||
/* syslogs who connected to where */
|
/* syslogs who connected to where */
|
||||||
void log_connection(struct connection *cnx)
|
void log_connection(struct connection *cnx)
|
||||||
{
|
{
|
||||||
struct sockaddr peeraddr, localaddr;
|
struct sockaddr_storage peeraddr; /* Who's connecting to sshd */
|
||||||
|
struct sockaddr_storage listenaddr; /* Where is it connecting to */
|
||||||
|
struct sockaddr_storage forwardfromaddr; /* Where is it forwarded from */
|
||||||
|
struct sockaddr_storage targetaddr; /* Where is it forwarded to */
|
||||||
socklen_t size = sizeof(peeraddr);
|
socklen_t size = sizeof(peeraddr);
|
||||||
char buf[64], buf2[64];
|
#define MAX_NAMELENGTH (NI_MAXHOST + NI_MAXSERV + 1)
|
||||||
|
char buf[MAX_NAMELENGTH], buf2[MAX_NAMELENGTH], buf3[MAX_NAMELENGTH], buf4[MAX_NAMELENGTH];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = getpeername(cnx->q[0].fd, &peeraddr, &size);
|
memset(&peeraddr, 0, sizeof(peeraddr));
|
||||||
|
memset(&listenaddr, 0, sizeof(listenaddr));
|
||||||
|
memset(&forwardfromaddr, 0, sizeof(forwardfromaddr));
|
||||||
|
memset(&targetaddr, 0, sizeof(targetaddr));
|
||||||
|
|
||||||
|
res = getpeername(cnx->q[0].fd, (struct sockaddr*)&peeraddr, &size);
|
||||||
if (res == -1) return; /* that should never happen, right? */
|
if (res == -1) return; /* that should never happen, right? */
|
||||||
|
|
||||||
res = getpeername(cnx->q[1].fd, &localaddr, &size);
|
size = sizeof(listenaddr);
|
||||||
if (res == -1) return; /* that should never happen, right? */
|
res = getsockname(cnx->q[0].fd, (struct sockaddr*)&listenaddr, &size);
|
||||||
|
if (res == -1) return;
|
||||||
|
|
||||||
log_message(LOG_INFO, "connection from %s forwarded to %s\n",
|
size = sizeof(targetaddr);
|
||||||
sprintaddr(buf, sizeof(buf), &peeraddr), sprintaddr(buf2, sizeof(buf2), &localaddr));
|
res = getpeername(cnx->q[1].fd, (struct sockaddr*)&targetaddr, &size);
|
||||||
|
if (res == -1) return;
|
||||||
|
|
||||||
|
size = sizeof(forwardfromaddr);
|
||||||
|
res = getsockname(cnx->q[1].fd, (struct sockaddr*)&forwardfromaddr, &size);
|
||||||
|
if (res == -1) return;
|
||||||
|
|
||||||
|
log_message(LOG_INFO, "connection from %s to %s forwarded from %s to %s\n",
|
||||||
|
sprintaddr(buf, sizeof(buf), &peeraddr),
|
||||||
|
sprintaddr(buf2, sizeof(buf2), &listenaddr),
|
||||||
|
sprintaddr(buf3, sizeof(buf3), &forwardfromaddr),
|
||||||
|
sprintaddr(buf4, sizeof(buf4), &targetaddr));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,27 +446,38 @@ void log_connection(struct connection *cnx)
|
|||||||
*
|
*
|
||||||
* Returns -1 if access is denied, 0 otherwise
|
* Returns -1 if access is denied, 0 otherwise
|
||||||
*/
|
*/
|
||||||
int check_access_rights(int in_socket, const char* service)
|
int check_access_rights(int in_socket, char* service)
|
||||||
{
|
{
|
||||||
#ifdef LIBWRAP
|
#ifdef LIBWRAP
|
||||||
struct sockaddr peeraddr;
|
struct sockaddr peeraddr;
|
||||||
socklen_t size = sizeof(peeraddr);
|
socklen_t size = sizeof(peeraddr);
|
||||||
char addr_str[1024];
|
char addr_str[NI_MAXHOST], host[NI_MAXHOST];
|
||||||
struct hostent *host;
|
|
||||||
struct in_addr addr;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = getpeername(in_socket, &peeraddr, &size);
|
res = getpeername(in_socket, &peeraddr, &size);
|
||||||
CHECK_RES_DIE(res, "getpeername");
|
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);
|
/* extract peer address */
|
||||||
host = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
|
res = getnameinfo(&peeraddr, size, addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST);
|
||||||
|
if (res) {
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "getnameinfo(NI_NUMERICHOST):%s\n", gai_strerror(res));
|
||||||
|
strcpy(addr_str, STRING_UNKNOWN);
|
||||||
|
}
|
||||||
|
/* extract peer name */
|
||||||
|
strcpy(host, STRING_UNKNOWN);
|
||||||
|
if (!numeric) {
|
||||||
|
res = getnameinfo(&peeraddr, size, host, sizeof(host), NULL, 0, NI_NAMEREQD);
|
||||||
|
if (res) {
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "getnameinfo(NI_NAMEREQD):%s\n", gai_strerror(res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!hosts_ctl(service, (host ? host->h_name : STRING_UNKNOWN), addr_str, STRING_UNKNOWN)) {
|
if (!hosts_ctl(service, host, addr_str, STRING_UNKNOWN)) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf(stderr, "access denied\n");
|
fprintf(stderr, "access denied\n");
|
||||||
log_connection(in_socket, "access denied");
|
log_message(LOG_INFO, "connection from %s(%s): access denied", host, addr_str);
|
||||||
close(in_socket);
|
close(in_socket);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -489,14 +560,62 @@ void printsettings(void)
|
|||||||
sprintaddr(buf, sizeof(buf), &protocols[i].saddr),
|
sprintaddr(buf, sizeof(buf), &protocols[i].saddr),
|
||||||
protocols[i].service);
|
protocols[i].service);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "listening on %s\n", sprintaddr(buf, sizeof(buf), &addr_listen));
|
fprintf(stderr, "listening on:\n");
|
||||||
|
for (i = 0; i < num_addr_listen; i++) {
|
||||||
|
fprintf(stderr, "\t%s\n", sprintaddr(buf, sizeof(buf), &addr_listen[i]));
|
||||||
|
}
|
||||||
|
fprintf(stderr, "timeout to ssh: %d\n", probing_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adds protocols to the list of options, so command-line parsing uses the
|
||||||
|
* protocol definition array
|
||||||
|
* options: array of options to add to; must be big enough
|
||||||
|
* n_opts: number of options in *options before calling (i.e. where to append)
|
||||||
|
* prot: array of protocols
|
||||||
|
* n_prots: number of protocols in *prot
|
||||||
|
* */
|
||||||
|
#define PROT_SHIFT 1000 /* protocol options will be 1000, 1001, etc */
|
||||||
|
void append_protocols(struct option *options, int n_opts, struct proto *prot, int n_prots)
|
||||||
|
{
|
||||||
|
int o, p;
|
||||||
|
|
||||||
|
for (o = n_opts, p = 0; p < n_prots; o++, p++) {
|
||||||
|
options[o].name = prot[p].description;
|
||||||
|
options[o].has_arg = required_argument;
|
||||||
|
options[o].flag = 0;
|
||||||
|
options[o].val = p + PROT_SHIFT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_cmdline(int argc, char* argv[])
|
void parse_cmdline(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int c, affected = 0;
|
||||||
|
struct option const_options[] = {
|
||||||
|
{ "inetd", no_argument, &inetd, 1 },
|
||||||
|
{ "foreground", no_argument, &foreground, 1 },
|
||||||
|
{ "verbose", no_argument, &verbose, 1 },
|
||||||
|
{ "numeric", no_argument, &numeric, 1 },
|
||||||
|
{ "user", required_argument, 0, 'u' },
|
||||||
|
{ "pidfile", required_argument, 0, 'P' },
|
||||||
|
{ "timeout", required_argument, 0, 't' },
|
||||||
|
{ "listen", required_argument, 0, 'p' },
|
||||||
|
};
|
||||||
|
struct option all_options[ARRAY_SIZE(const_options) + ARRAY_SIZE(protocols) + 1];
|
||||||
|
|
||||||
|
memset(all_options, 0, sizeof(all_options));
|
||||||
|
memcpy(all_options, const_options, sizeof(const_options));
|
||||||
|
append_protocols(all_options, ARRAY_SIZE(const_options), protocols, ARRAY_SIZE(protocols));
|
||||||
|
|
||||||
|
while ((c = getopt_long_only(argc, argv, "t:l:s:o:T:p:VP:", all_options, NULL)) != -1) {
|
||||||
|
if (c == 0) continue;
|
||||||
|
|
||||||
|
if (c >= PROT_SHIFT) {
|
||||||
|
affected++;
|
||||||
|
protocols[c - PROT_SHIFT].affected = 1;
|
||||||
|
resolve_name(&protocols[c - PROT_SHIFT].saddr, optarg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "t:l:s:o:p:P:ivfVu:")) != EOF) {
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
@ -504,34 +623,9 @@ void parse_cmdline(int argc, char* argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
resolve_name(&addr_listen, optarg);
|
num_addr_listen++;
|
||||||
break;
|
addr_listen = realloc(addr_listen, num_addr_listen * sizeof(addr_listen[0]));
|
||||||
|
resolve_name(&addr_listen[num_addr_listen - 1], optarg);
|
||||||
case 'l':
|
|
||||||
protocols[PROT_SSL].affected = 1;
|
|
||||||
resolve_name(&protocols[PROT_SSL].saddr, optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 's':
|
|
||||||
protocols[PROT_SSH].affected = 1;
|
|
||||||
resolve_name(&protocols[PROT_SSH].saddr, optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'o':
|
|
||||||
protocols[PROT_OPENVPN].affected = 1;
|
|
||||||
resolve_name(&protocols[PROT_OPENVPN].saddr, optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'i':
|
|
||||||
inetd = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'f':
|
|
||||||
foreground = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'v':
|
|
||||||
verbose += 1;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'V':
|
case 'V':
|
||||||
@ -551,6 +645,17 @@ void parse_cmdline(int argc, char* argv[])
|
|||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!affected) {
|
||||||
|
fprintf(stderr, "At least one target protocol must be specified.\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!num_addr_listen) {
|
||||||
|
fprintf(stderr, "No listening address specified; use at least one -p option\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -560,22 +665,13 @@ int main(int argc, char *argv[])
|
|||||||
extern int optind;
|
extern int optind;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
int listen_socket;
|
int *listen_sockets;
|
||||||
|
|
||||||
/* Init defaults */
|
/* Init defaults */
|
||||||
char listen_str[] = "0.0.0.0:443";
|
|
||||||
char ssl_str[] = "localhost:443";
|
|
||||||
char ssh_str[] = "localhost:22";
|
|
||||||
pid_file = "/var/run/sslh.pid";
|
pid_file = "/var/run/sslh.pid";
|
||||||
user_name = "nobody";
|
user_name = "nobody";
|
||||||
foreground = 0;
|
foreground = 0;
|
||||||
|
|
||||||
resolve_name(&addr_listen, listen_str);
|
|
||||||
protocols[PROT_SSL].affected = 1;
|
|
||||||
resolve_name(&protocols[PROT_SSL].saddr, ssl_str);
|
|
||||||
protocols[PROT_SSH].affected = 1;
|
|
||||||
resolve_name(&protocols[PROT_SSH].saddr, ssh_str);
|
|
||||||
|
|
||||||
parse_cmdline(argc, argv);
|
parse_cmdline(argc, argv);
|
||||||
|
|
||||||
if (inetd)
|
if (inetd)
|
||||||
@ -588,7 +684,9 @@ int main(int argc, char *argv[])
|
|||||||
if (verbose)
|
if (verbose)
|
||||||
printsettings();
|
printsettings();
|
||||||
|
|
||||||
listen_socket = start_listen_socket(&addr_listen);
|
listen_sockets = malloc(num_addr_listen * sizeof(*listen_sockets));
|
||||||
|
start_listen_sockets(listen_sockets, addr_listen, num_addr_listen);
|
||||||
|
free(addr_listen);
|
||||||
|
|
||||||
if (!foreground)
|
if (!foreground)
|
||||||
if (fork() > 0) exit(0); /* Detach */
|
if (fork() > 0) exit(0); /* Detach */
|
||||||
@ -608,7 +706,7 @@ int main(int argc, char *argv[])
|
|||||||
/* Open syslog connection */
|
/* Open syslog connection */
|
||||||
setup_syslog(argv[0]);
|
setup_syslog(argv[0]);
|
||||||
|
|
||||||
main_loop(listen_socket);
|
main_loop(listen_sockets, num_addr_listen);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
17
common.h
17
common.h
@ -52,15 +52,16 @@ enum connection_state {
|
|||||||
typedef enum protocol_type {
|
typedef enum protocol_type {
|
||||||
PROT_SSH,
|
PROT_SSH,
|
||||||
PROT_OPENVPN,
|
PROT_OPENVPN,
|
||||||
|
PROT_TINC,
|
||||||
PROT_SSL,
|
PROT_SSL,
|
||||||
} T_PROTO_ID;
|
} T_PROTO_ID;
|
||||||
|
|
||||||
/* For each protocol we need: */
|
/* For each protocol we need: */
|
||||||
struct proto {
|
struct proto {
|
||||||
int affected; /* are we actually using it? */
|
int affected; /* are we actually using it? */
|
||||||
char* description; /* a string that says what it is (for logging) */
|
char* description; /* a string that says what it is (for logging and command-line parsing) */
|
||||||
char* service; /* service name to do libwrap checks */
|
char* service; /* service name to do libwrap checks */
|
||||||
struct sockaddr saddr; /* where to switch that protocol */
|
struct sockaddr_storage saddr; /* where to switch that protocol */
|
||||||
int (*probe)(const char*, int); /* function to probe that protocol */
|
int (*probe)(const char*, int); /* function to probe that protocol */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -93,13 +94,13 @@ struct connection {
|
|||||||
|
|
||||||
/* common.c */
|
/* common.c */
|
||||||
void init_cnx(struct connection *cnx);
|
void init_cnx(struct connection *cnx);
|
||||||
int start_listen_socket(struct sockaddr *addr);
|
void start_listen_sockets(int sockfd[], struct sockaddr_storage addr[], int num_addr);
|
||||||
int fd2fd(struct queue *target, struct queue *from);
|
int fd2fd(struct queue *target, struct queue *from);
|
||||||
|
char* sprintaddr(char* buf, size_t size, struct sockaddr_storage* s);
|
||||||
|
void resolve_name(struct sockaddr_storage *sock, char* fullname) ;
|
||||||
T_PROTO_ID probe_client_protocol(struct connection *cnx);
|
T_PROTO_ID probe_client_protocol(struct connection *cnx);
|
||||||
char* sprintaddr(char* buf, size_t size, struct sockaddr* s);
|
|
||||||
void resolve_name(struct sockaddr *sock, char* fullname) ;
|
|
||||||
void log_connection(struct connection *cnx);
|
void log_connection(struct connection *cnx);
|
||||||
int check_access_rights(int in_socket, const char* service);
|
int check_access_rights(int in_socket, char* service);
|
||||||
void setup_signals(void);
|
void setup_signals(void);
|
||||||
void setup_syslog(char* bin_name);
|
void setup_syslog(char* bin_name);
|
||||||
void drop_privileges(char* user_name);
|
void drop_privileges(char* user_name);
|
||||||
@ -114,7 +115,7 @@ int defer_write(struct queue *q, void* data, int data_size);
|
|||||||
int flush_defered(struct queue *q);
|
int flush_defered(struct queue *q);
|
||||||
|
|
||||||
extern int probing_timeout, verbose, inetd;
|
extern int probing_timeout, verbose, inetd;
|
||||||
extern struct sockaddr addr_listen, addr_ssl, addr_ssh, addr_openvpn;
|
extern struct sockaddr_storage *addr_listen, addr_ssl, addr_ssh, addr_openvpn;
|
||||||
extern const char* USAGE_STRING;
|
extern const char* USAGE_STRING;
|
||||||
extern char* user_name, *pid_file;
|
extern char* user_name, *pid_file;
|
||||||
extern const char* server_type;
|
extern const char* server_type;
|
||||||
@ -122,6 +123,6 @@ extern const char* server_type;
|
|||||||
/* sslh-fork.c */
|
/* sslh-fork.c */
|
||||||
void start_shoveler(int);
|
void start_shoveler(int);
|
||||||
|
|
||||||
void main_loop(int);
|
void main_loop(int *listen_sockets, int num_addr_listen);
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ DAEMON=$PREFIX/sbin/sslh
|
|||||||
start()
|
start()
|
||||||
{
|
{
|
||||||
echo "Start services: sslh"
|
echo "Start services: sslh"
|
||||||
$DAEMON -u nobody -p ${LISTEN} -s ${SSH} -l ${SSL}
|
$DAEMON --user nobody --listen ${LISTEN} --ssh ${SSH} --ssl ${SSL}
|
||||||
logger -t ${tag} -p ${facility} -i 'Started sslh'
|
logger -t ${tag} -p ${facility} -i 'Started sslh'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
SSLH="/usr/local/sbin/sslh"
|
SSLH="/usr/local/sbin/sslh"
|
||||||
PIDFILE="/var/run/sslh"
|
PIDFILE="/var/run/sslh"
|
||||||
|
|
||||||
OPTIONS="-p 0.0.0.0:8443 -l 127.0.0.1:443 -s 127.0.0.1:22"
|
OPTIONS="-p 0.0.0.0:8443 --ssl 127.0.0.1:443 --ssh 127.0.0.1:22"
|
||||||
|
|
||||||
if [ -f /etc/sysconfig/sslh ]; then
|
if [ -f /etc/sysconfig/sslh ]; then
|
||||||
. /etc/sysconfig/sslh
|
. /etc/sysconfig/sslh
|
||||||
|
38
sslh-fork.c
38
sslh-fork.c
@ -68,7 +68,7 @@ void start_shoveler(int in_socket)
|
|||||||
{
|
{
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
struct sockaddr *saddr;
|
struct sockaddr_storage *saddr;
|
||||||
int res;
|
int res;
|
||||||
int out_socket;
|
int out_socket;
|
||||||
char *target;
|
char *target;
|
||||||
@ -103,8 +103,8 @@ void start_shoveler(int in_socket)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Connect the target socket */
|
/* Connect the target socket */
|
||||||
out_socket = socket(AF_INET, SOCK_STREAM, 0);
|
out_socket = socket(saddr->ss_family, SOCK_STREAM, 0);
|
||||||
res = connect(out_socket, saddr, sizeof(addr_ssl));
|
res = connect(out_socket, (struct sockaddr*)saddr, sizeof(addr_ssl));
|
||||||
CHECK_RES_DIE(res, "connect");
|
CHECK_RES_DIE(res, "connect");
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf(stderr, "connected to something\n");
|
fprintf(stderr, "connected to something\n");
|
||||||
@ -126,23 +126,27 @@ void start_shoveler(int in_socket)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_loop(int listen_socket)
|
void main_loop(int *listen_sockets, int num_addr_listen)
|
||||||
{
|
{
|
||||||
int in_socket;
|
int in_socket, i;
|
||||||
|
|
||||||
while (1)
|
for (i = 0; i < num_addr_listen; i++) {
|
||||||
{
|
if (!fork()) {
|
||||||
in_socket = accept(listen_socket, 0, 0);
|
while (1)
|
||||||
if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
|
{
|
||||||
|
in_socket = accept(listen_sockets[i], 0, 0);
|
||||||
|
if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
|
||||||
|
|
||||||
if (!fork())
|
if (!fork())
|
||||||
{
|
{
|
||||||
close(listen_socket);
|
close(listen_sockets[i]);
|
||||||
start_shoveler(in_socket);
|
start_shoveler(in_socket);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
close(in_socket);
|
close(in_socket);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The actual main is in common.c: it's the same for both version of
|
/* The actual main is in common.c: it's the same for both version of
|
||||||
|
@ -111,15 +111,15 @@ int accept_new_connection(int listen_socket, struct connection *cnx[], int* cnx_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Connect queue 1 of connection to SSL; returns new file descriptor */
|
/* Connect queue 1 of connection to SSL; returns new file descriptor */
|
||||||
int connect_queue(struct connection *cnx, struct sockaddr *addr,
|
int connect_queue(struct connection *cnx, struct sockaddr_storage *addr,
|
||||||
char* cnx_name,
|
char* cnx_name,
|
||||||
fd_set *fds_r, fd_set *fds_w)
|
fd_set *fds_r, fd_set *fds_w)
|
||||||
{
|
{
|
||||||
struct queue *q = &cnx->q[1];
|
struct queue *q = &cnx->q[1];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
q->fd = socket(AF_INET, SOCK_STREAM, 0);
|
q->fd = socket(addr->ss_family, SOCK_STREAM, 0);
|
||||||
res = connect(q->fd, addr, sizeof(*addr));
|
res = connect(q->fd, (struct sockaddr*)addr, sizeof(*addr));
|
||||||
log_connection(cnx);
|
log_connection(cnx);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
tidy_connection(cnx, fds_r, fds_w);
|
tidy_connection(cnx, fds_r, fds_w);
|
||||||
@ -188,7 +188,7 @@ int is_fd_active(int fd, fd_set* set)
|
|||||||
* That way, each pair of file descriptor (read from one, write to the other)
|
* That way, each pair of file descriptor (read from one, write to the other)
|
||||||
* is monitored either for read or for write, but never for both.
|
* is monitored either for read or for write, but never for both.
|
||||||
*/
|
*/
|
||||||
void main_loop(int listen_socket)
|
void main_loop(int *listen_sockets, int num_addr_listen)
|
||||||
{
|
{
|
||||||
fd_set fds_r, fds_w; /* reference fd sets (used to init the next 2) */
|
fd_set fds_r, fds_w; /* reference fd sets (used to init the next 2) */
|
||||||
fd_set readfds, writefds; /* working read and write fd sets */
|
fd_set readfds, writefds; /* working read and write fd sets */
|
||||||
@ -203,10 +203,12 @@ void main_loop(int listen_socket)
|
|||||||
|
|
||||||
FD_ZERO(&fds_r);
|
FD_ZERO(&fds_r);
|
||||||
FD_ZERO(&fds_w);
|
FD_ZERO(&fds_w);
|
||||||
FD_SET(listen_socket, &fds_r);
|
|
||||||
max_fd = listen_socket + 1;
|
|
||||||
|
|
||||||
set_nonblock(listen_socket);
|
for (i = 0; i < num_addr_listen; i++) {
|
||||||
|
FD_SET(listen_sockets[i], &fds_r);
|
||||||
|
set_nonblock(listen_sockets[i]);
|
||||||
|
}
|
||||||
|
max_fd = listen_sockets[num_addr_listen-1] + 1;
|
||||||
|
|
||||||
cnx_num_alloc = getpagesize() / sizeof(struct connection);
|
cnx_num_alloc = getpagesize() / sizeof(struct connection);
|
||||||
|
|
||||||
@ -231,16 +233,18 @@ void main_loop(int listen_socket)
|
|||||||
|
|
||||||
|
|
||||||
/* Check main socket for new connections */
|
/* Check main socket for new connections */
|
||||||
if (FD_ISSET(listen_socket, &readfds)) {
|
for (i = 0; i < num_addr_listen; i++) {
|
||||||
in_socket = accept_new_connection(listen_socket, &cnx, &num_cnx);
|
if (FD_ISSET(listen_sockets[i], &readfds)) {
|
||||||
num_probing++;
|
in_socket = accept_new_connection(listen_sockets[i], &cnx, &num_cnx);
|
||||||
|
num_probing++;
|
||||||
|
|
||||||
if (in_socket > 0) {
|
if (in_socket > 0) {
|
||||||
FD_SET(in_socket, &fds_r);
|
FD_SET(in_socket, &fds_r);
|
||||||
if (in_socket >= max_fd)
|
if (in_socket >= max_fd)
|
||||||
max_fd = in_socket + 1;;
|
max_fd = in_socket + 1;;
|
||||||
|
}
|
||||||
|
FD_CLR(listen_sockets[i], &readfds);
|
||||||
}
|
}
|
||||||
FD_CLR(listen_socket, &readfds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check all sockets for write activity */
|
/* Check all sockets for write activity */
|
||||||
|
54
sslh.pod
54
sslh.pod
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
=head1 SYNOPSIS
|
=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<-o> I<target address for OpenVPN>] [B<-u> I<username>] [B<-P> I<pidfile>] [-v] [-i] [-V] [-f]
|
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]
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
@ -57,69 +57,79 @@ defined in F</etc/hosts.allow> and F</etc/hosts.deny>.
|
|||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
=item B<-t> I<num>
|
=item B<-t> I<num>, B<--timeout> I<num>
|
||||||
|
|
||||||
Timeout before a connection is considered to be SSH. Default
|
Timeout before a connection is considered to be SSH. Default
|
||||||
is 2s.
|
is 2s.
|
||||||
|
|
||||||
=item B<-p> I<listening address>
|
=item B<-p> I<listening address>, B<--listen> I<listening address>
|
||||||
|
|
||||||
Interface and port on which to listen, e.g. I<foobar:443>,
|
Interface and port on which to listen, e.g. I<foobar:443>,
|
||||||
where I<foobar> is the name of an interface (typically the
|
where I<foobar> is the name of an interface (typically the
|
||||||
IP address on which the Internet connection ends up).
|
IP address on which the Internet connection ends up).
|
||||||
|
|
||||||
Defaults to I<0.0.0.0:443> (listen to port 443 on all
|
This can be specified several times to bind B<sslh> to
|
||||||
available interfaces).
|
several addresses.
|
||||||
|
|
||||||
=item B<-l> I<target address for SSL>
|
=item B<--ssl> I<target address>
|
||||||
|
|
||||||
Interface and port on which to forward SSL connection,
|
Interface and port on which to forward SSL connection,
|
||||||
typically I<localhost:443>.
|
typically I<localhost:443>.
|
||||||
|
|
||||||
Defaults to I<localhost:443> (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
|
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
|
B<httpd> to listen on I<localhost:443>: this allows clients
|
||||||
inside your network to just connect directly to B<httpd>.
|
inside your network to just connect directly to B<httpd>.
|
||||||
|
|
||||||
=item B<-s> I<target address for SSH>
|
=item B<--ssh> I<target address>
|
||||||
|
|
||||||
Interface and port on which to forward SSH connection,
|
Interface and port on which to forward SSH connections,
|
||||||
defaults to I<localhost:22>.
|
typically I<localhost:22>.
|
||||||
|
|
||||||
=item B<-o> I<target address for OpenVPN>
|
=item B<--openvpn> I<target address>
|
||||||
|
|
||||||
Interface and port on which to forward OpenVPN connections.
|
Interface and port on which to forward OpenVPN connections,
|
||||||
This parameter is optional, and has no default. If not
|
typically I<localhost:1194>.
|
||||||
specified, incoming OpenVPN connections will not be detected
|
|
||||||
as such and treated the same as SSL.
|
|
||||||
|
|
||||||
=item B<-v>
|
=item B<--tinc> I<target address>
|
||||||
|
|
||||||
|
Interface and port on which to forward tinc connections,
|
||||||
|
typically I<localhost:655>.
|
||||||
|
|
||||||
|
This is experimental. If you use this feature, please report
|
||||||
|
the results (even if it works!)
|
||||||
|
|
||||||
|
=item B<-v>, B<--verbose>
|
||||||
|
|
||||||
Increase verboseness.
|
Increase verboseness.
|
||||||
|
|
||||||
|
=item B<-n>, B<--numeric>
|
||||||
|
|
||||||
|
Do not attempt to resolve hostnames: logs will contain IP
|
||||||
|
addresses. This is mostly useful if the system's DNS is slow
|
||||||
|
and running the I<sslh-select> variant, as DNS requests will
|
||||||
|
hang all connections.
|
||||||
|
|
||||||
=item B<-V>
|
=item B<-V>
|
||||||
|
|
||||||
Prints B<sslh> version.
|
Prints B<sslh> version.
|
||||||
|
|
||||||
=item B<-u> I<username>
|
=item B<-u> I<username>, B<--user> I<username>
|
||||||
|
|
||||||
Requires to run under the specified username. Defaults to
|
Requires to run under the specified username. Defaults to
|
||||||
I<nobody> (which is not perfect -- ideally B<sslh> should
|
I<nobody> (which is not perfect -- ideally B<sslh> should
|
||||||
run under its own UID).
|
run under its own UID).
|
||||||
|
|
||||||
=item B<-P> I<pidfile>
|
=item B<-P> I<pidfile>, B<--pid-file> I<pidfile>
|
||||||
|
|
||||||
Specifies the file in which to write the PID of the main
|
Specifies the file in which to write the PID of the main
|
||||||
server. Defaults to I</var/run/sslh.pid>.
|
server. Defaults to I</var/run/sslh.pid>.
|
||||||
|
|
||||||
=item B<-i>
|
=item B<-i>, B<--inetd>
|
||||||
|
|
||||||
Runs as an I<inetd> server. Options B<-P> (PID file), B<-p>
|
Runs as an I<inetd> server. Options B<-P> (PID file), B<-p>
|
||||||
(listen address), B<-u> (user) are ignored.
|
(listen address), B<-u> (user) are ignored.
|
||||||
|
|
||||||
=item B<-f>
|
=item B<-f>, B<--foreground>
|
||||||
|
|
||||||
Runs in foreground. The server will not fork and will remain connected
|
Runs in foreground. The server will not fork and will remain connected
|
||||||
to the terminal. Messages normally sent to B<syslog> will also be sent
|
to the terminal. Messages normally sent to B<syslog> will also be sent
|
||||||
|
Loading…
Reference in New Issue
Block a user