mirror of
https://github.com/yrutschle/sslh.git
synced 2025-04-12 23:27:15 +03:00
config file now read to struct with c2s; command line no longer works
This commit is contained in:
parent
7af31c45c9
commit
e7ce929020
7
Makefile
7
Makefile
@ -25,7 +25,7 @@ CC ?= gcc
|
|||||||
CFLAGS ?=-Wall -g $(CFLAGS_COV)
|
CFLAGS ?=-Wall -g $(CFLAGS_COV)
|
||||||
|
|
||||||
LIBS=
|
LIBS=
|
||||||
OBJS=common.o sslh-main.o probe.o tls.o
|
OBJS=sslh-conf.o common.o sslh-main.o probe.o tls.o
|
||||||
|
|
||||||
CONDITIONAL_TARGETS=
|
CONDITIONAL_TARGETS=
|
||||||
|
|
||||||
@ -72,6 +72,9 @@ sslh: sslh-fork sslh-select
|
|||||||
|
|
||||||
$(OBJS): version.h
|
$(OBJS): version.h
|
||||||
|
|
||||||
|
sslh-conf.c: sslhconf.cfg
|
||||||
|
conf2struct sslhconf.cfg
|
||||||
|
|
||||||
sslh-fork: version.h $(OBJS) sslh-fork.o Makefile common.h
|
sslh-fork: version.h $(OBJS) sslh-fork.o Makefile common.h
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -o sslh-fork sslh-fork.o $(OBJS) $(LIBS)
|
$(CC) $(CFLAGS) $(LDFLAGS) -o sslh-fork sslh-fork.o $(OBJS) $(LIBS)
|
||||||
#strip sslh-fork
|
#strip sslh-fork
|
||||||
@ -112,7 +115,7 @@ uninstall:
|
|||||||
update-rc.d sslh remove
|
update-rc.d sslh remove
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f tags cscope.*
|
rm -f tags sslh-conf.c sslh-conf.h cscope.*
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f sslh-fork sslh-select echosrv version.h $(MAN) systemd-sslh-generator *.o *.gcov *.gcno *.gcda *.png *.html *.css *.info
|
rm -f sslh-fork sslh-select echosrv version.h $(MAN) systemd-sslh-generator *.o *.gcov *.gcno *.gcda *.png *.html *.css *.info
|
||||||
|
69
common.c
69
common.c
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "probe.h"
|
#include "probe.h"
|
||||||
|
#include "sslh-conf.h"
|
||||||
|
|
||||||
/* Added to make the code compilable under CYGWIN
|
/* Added to make the code compilable under CYGWIN
|
||||||
* */
|
* */
|
||||||
@ -30,18 +31,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Settings that depend on the command line. They're set in main(), but also
|
* Settings that depend on the command line or the config file
|
||||||
* used in other places in common.c, and it'd be heavy-handed to pass it all as
|
|
||||||
* parameters
|
|
||||||
*/
|
*/
|
||||||
int verbose = 0;
|
struct config_item cfg;
|
||||||
int probing_timeout = 2;
|
|
||||||
int inetd = 0;
|
|
||||||
int foreground = 0;
|
|
||||||
int background = 0;
|
|
||||||
int transparent = 0;
|
|
||||||
int numeric = 0;
|
|
||||||
const char *user_name, *pid_file, *chroot_path, *facility = "auth";
|
|
||||||
|
|
||||||
struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */
|
struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */
|
||||||
|
|
||||||
@ -122,7 +114,7 @@ int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "listening to %d addresses\n", num_addr);
|
fprintf(stderr, "listening to %d addresses\n", num_addr);
|
||||||
|
|
||||||
*sockfd = malloc(num_addr * sizeof(*sockfd[0]));
|
*sockfd = malloc(num_addr * sizeof(*sockfd[0]));
|
||||||
@ -272,9 +264,9 @@ int connect_addr(struct connection *cnx, int fd_from)
|
|||||||
|
|
||||||
for (a = cnx->proto->saddr; a; a = a->ai_next) {
|
for (a = cnx->proto->saddr; a; a = a->ai_next) {
|
||||||
/* When transparent, make sure both connections use the same address family */
|
/* When transparent, make sure both connections use the same address family */
|
||||||
if (transparent && a->ai_family != from.ai_addr->sa_family)
|
if (cfg.transparent && a->ai_family != from.ai_addr->sa_family)
|
||||||
continue;
|
continue;
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "connecting to %s family %d len %d\n",
|
fprintf(stderr, "connecting to %s family %d len %d\n",
|
||||||
sprintaddr(buf, sizeof(buf), a),
|
sprintaddr(buf, sizeof(buf), a),
|
||||||
a->ai_addr->sa_family, a->ai_addrlen);
|
a->ai_addr->sa_family, a->ai_addrlen);
|
||||||
@ -283,16 +275,16 @@ int connect_addr(struct connection *cnx, int fd_from)
|
|||||||
fd = socket(a->ai_family, SOCK_STREAM, 0);
|
fd = socket(a->ai_family, SOCK_STREAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
log_message(LOG_ERR, "forward to %s failed:socket: %s\n",
|
log_message(LOG_ERR, "forward to %s failed:socket: %s\n",
|
||||||
cnx->proto->description, strerror(errno));
|
cnx->proto->name, strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
if (transparent) {
|
if (cfg.transparent) {
|
||||||
res = bind_peer(fd, fd_from);
|
res = bind_peer(fd, fd_from);
|
||||||
CHECK_RES_RETURN(res, "bind_peer");
|
CHECK_RES_RETURN(res, "bind_peer");
|
||||||
}
|
}
|
||||||
res = connect(fd, a->ai_addr, a->ai_addrlen);
|
res = connect(fd, a->ai_addr, a->ai_addrlen);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
log_message(LOG_ERR, "forward to %s failed:connect: %s\n",
|
log_message(LOG_ERR, "forward to %s failed:connect: %s\n",
|
||||||
cnx->proto->description, strerror(errno));
|
cnx->proto->name, strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
} else {
|
} else {
|
||||||
if (cnx->proto->keepalive) {
|
if (cnx->proto->keepalive) {
|
||||||
@ -312,7 +304,7 @@ int defer_write(struct queue *q, void* data, int data_size)
|
|||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
ptrdiff_t data_offset = q->deferred_data - q->begin_deferred_data;
|
ptrdiff_t data_offset = q->deferred_data - q->begin_deferred_data;
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "**** writing deferred on fd %d\n", q->fd);
|
fprintf(stderr, "**** writing deferred on fd %d\n", q->fd);
|
||||||
|
|
||||||
p = realloc(q->begin_deferred_data, data_offset + q->deferred_data_size + data_size);
|
p = realloc(q->begin_deferred_data, data_offset + q->deferred_data_size + data_size);
|
||||||
@ -335,7 +327,7 @@ int flush_deferred(struct queue *q)
|
|||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "flushing deferred data to fd %d\n", q->fd);
|
fprintf(stderr, "flushing deferred data to fd %d\n", q->fd);
|
||||||
|
|
||||||
n = write(q->fd, q->deferred_data, q->deferred_data_size);
|
n = write(q->fd, q->deferred_data, q->deferred_data_size);
|
||||||
@ -395,7 +387,7 @@ int fd2fd(struct queue *target_q, struct queue *from_q)
|
|||||||
if (size_r == -1) {
|
if (size_r == -1) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "reading 0 from %d\n", from);
|
fprintf(stderr, "reading 0 from %d\n", from);
|
||||||
return FD_NODATA;
|
return FD_NODATA;
|
||||||
|
|
||||||
@ -444,7 +436,7 @@ char* sprintaddr(char* buf, size_t size, struct addrinfo *a)
|
|||||||
res = getnameinfo(a->ai_addr, a->ai_addrlen,
|
res = getnameinfo(a->ai_addr, a->ai_addrlen,
|
||||||
host, sizeof(host),
|
host, sizeof(host),
|
||||||
serv, sizeof(serv),
|
serv, sizeof(serv),
|
||||||
numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 );
|
cfg.numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 );
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
log_message(LOG_ERR, "sprintaddr:getnameinfo: %s\n", gai_strerror(res));
|
log_message(LOG_ERR, "sprintaddr:getnameinfo: %s\n", gai_strerror(res));
|
||||||
@ -469,26 +461,16 @@ char* sprintaddr(char* buf, size_t size, struct addrinfo *a)
|
|||||||
/* Turns a hostname and port (or service) into a list of struct addrinfo
|
/* Turns a hostname and port (or service) into a list of struct addrinfo
|
||||||
* returns 0 on success, -1 otherwise and logs error
|
* returns 0 on success, -1 otherwise and logs error
|
||||||
*/
|
*/
|
||||||
int resolve_split_name(struct addrinfo **out, const char* ct_host, const char* serv)
|
int resolve_split_name(struct addrinfo **out, char* host, char* serv)
|
||||||
{
|
{
|
||||||
struct addrinfo hint;
|
struct addrinfo hint;
|
||||||
char *end;
|
char *end;
|
||||||
int res;
|
int res;
|
||||||
char* host, *host_base;
|
|
||||||
|
|
||||||
memset(&hint, 0, sizeof(hint));
|
memset(&hint, 0, sizeof(hint));
|
||||||
hint.ai_family = PF_UNSPEC;
|
hint.ai_family = PF_UNSPEC;
|
||||||
hint.ai_socktype = SOCK_STREAM;
|
hint.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
/* Copy parameter so not to clobber data in libconfig */
|
|
||||||
res = asprintf(&host_base, "%s", ct_host);
|
|
||||||
if (res == -1) {
|
|
||||||
log_message(LOG_ERR, "asprintf: cannot allocate memory");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
host = host_base;
|
|
||||||
|
|
||||||
/* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets
|
/* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets
|
||||||
* around IP address */
|
* around IP address */
|
||||||
if (host[0] == '[') {
|
if (host[0] == '[') {
|
||||||
@ -504,7 +486,6 @@ int resolve_split_name(struct addrinfo **out, const char* ct_host, const char* s
|
|||||||
res = getaddrinfo(host, serv, &hint, out);
|
res = getaddrinfo(host, serv, &hint, out);
|
||||||
if (res)
|
if (res)
|
||||||
log_message(LOG_ERR, "%s `%s:%s'\n", gai_strerror(res), host, serv);
|
log_message(LOG_ERR, "%s `%s:%s'\n", gai_strerror(res), host, serv);
|
||||||
free(host_base);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,7 +524,7 @@ void log_message(int type, char* msg, ...)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, msg);
|
va_start(ap, msg);
|
||||||
if (foreground)
|
if (cfg.foreground)
|
||||||
vfprintf(stderr, msg, ap);
|
vfprintf(stderr, msg, ap);
|
||||||
else
|
else
|
||||||
vsyslog(type, msg, ap);
|
vsyslog(type, msg, ap);
|
||||||
@ -587,7 +568,7 @@ void log_connection(struct connection *cnx)
|
|||||||
sprintaddr(local, sizeof(local), &addr);
|
sprintaddr(local, sizeof(local), &addr);
|
||||||
|
|
||||||
log_message(LOG_INFO, "%s:connection from %s to %s forwarded from %s to %s\n",
|
log_message(LOG_INFO, "%s:connection from %s to %s forwarded from %s to %s\n",
|
||||||
cnx->proto->description,
|
cnx->proto->name,
|
||||||
peer,
|
peer,
|
||||||
service,
|
service,
|
||||||
local,
|
local,
|
||||||
@ -618,22 +599,22 @@ int check_access_rights(int in_socket, const char* service)
|
|||||||
/* extract peer address */
|
/* extract peer address */
|
||||||
res = getnameinfo(&peer.saddr, size, addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST);
|
res = getnameinfo(&peer.saddr, size, addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST);
|
||||||
if (res) {
|
if (res) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "getnameinfo(NI_NUMERICHOST):%s\n", gai_strerror(res));
|
fprintf(stderr, "getnameinfo(NI_NUMERICHOST):%s\n", gai_strerror(res));
|
||||||
strcpy(addr_str, STRING_UNKNOWN);
|
strcpy(addr_str, STRING_UNKNOWN);
|
||||||
}
|
}
|
||||||
/* extract peer name */
|
/* extract peer name */
|
||||||
strcpy(host, STRING_UNKNOWN);
|
strcpy(host, STRING_UNKNOWN);
|
||||||
if (!numeric) {
|
if (!cfg.numeric) {
|
||||||
res = getnameinfo(&peer.saddr, size, host, sizeof(host), NULL, 0, NI_NAMEREQD);
|
res = getnameinfo(&peer.saddr, size, host, sizeof(host), NULL, 0, NI_NAMEREQD);
|
||||||
if (res) {
|
if (res) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "getnameinfo(NI_NAMEREQD):%s\n", gai_strerror(res));
|
fprintf(stderr, "getnameinfo(NI_NAMEREQD):%s\n", gai_strerror(res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hosts_ctl(service, host, addr_str, STRING_UNKNOWN)) {
|
if (!hosts_ctl(service, host, addr_str, STRING_UNKNOWN)) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "access denied\n");
|
fprintf(stderr, "access denied\n");
|
||||||
log_message(LOG_INFO, "connection from %s(%s): access denied", host, addr_str);
|
log_message(LOG_INFO, "connection from %s(%s): access denied", host, addr_str);
|
||||||
close(in_socket);
|
close(in_socket);
|
||||||
@ -681,10 +662,10 @@ void setup_syslog(const char* bin_name) {
|
|||||||
CHECK_RES_DIE(res, "asprintf");
|
CHECK_RES_DIE(res, "asprintf");
|
||||||
|
|
||||||
for (fn = 0; facilitynames[fn].c_val != -1; fn++)
|
for (fn = 0; facilitynames[fn].c_val != -1; fn++)
|
||||||
if (strcmp(facilitynames[fn].c_name, facility) == 0)
|
if (strcmp(facilitynames[fn].c_name, cfg.syslog_facility) == 0)
|
||||||
break;
|
break;
|
||||||
if (facilitynames[fn].c_val == -1) {
|
if (facilitynames[fn].c_val == -1) {
|
||||||
fprintf(stderr, "Unknown facility %s\n", facility);
|
fprintf(stderr, "Unknown facility %s\n", cfg.syslog_facility);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,7 +696,7 @@ void set_capabilities(void) {
|
|||||||
cap_value_t cap_list[10];
|
cap_value_t cap_list[10];
|
||||||
int ncap = 0;
|
int ncap = 0;
|
||||||
|
|
||||||
if (transparent)
|
if (cfg.transparent)
|
||||||
cap_list[ncap++] = CAP_NET_ADMIN;
|
cap_list[ncap++] = CAP_NET_ADMIN;
|
||||||
|
|
||||||
caps = cap_init();
|
caps = cap_init();
|
||||||
@ -757,12 +738,12 @@ void drop_privileges(const char* user_name, const char* chroot_path)
|
|||||||
fprintf(stderr, "%s: not found\n", user_name);
|
fprintf(stderr, "%s: not found\n", user_name);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "turning into %s\n", user_name);
|
fprintf(stderr, "turning into %s\n", user_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chroot_path) {
|
if (chroot_path) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "chrooting into %s\n", chroot_path);
|
fprintf(stderr, "chrooting into %s\n", chroot_path);
|
||||||
|
|
||||||
res = chroot(chroot_path);
|
res = chroot(chroot_path);
|
||||||
|
5
common.h
5
common.h
@ -87,7 +87,7 @@ struct queue {
|
|||||||
struct connection {
|
struct connection {
|
||||||
enum connection_state state;
|
enum connection_state state;
|
||||||
time_t probe_timeout;
|
time_t probe_timeout;
|
||||||
struct proto *proto;
|
struct config_protocols_item* proto;
|
||||||
|
|
||||||
/* q[0]: queue for external connection (client);
|
/* q[0]: queue for external connection (client);
|
||||||
* q[1]: queue for internal connection (httpd or sshd);
|
* q[1]: queue for internal connection (httpd or sshd);
|
||||||
@ -114,7 +114,7 @@ void drop_privileges(const char* user_name, const char* chroot_path);
|
|||||||
void write_pid_file(const char* pidfile);
|
void write_pid_file(const char* pidfile);
|
||||||
void log_message(int type, char* msg, ...);
|
void log_message(int type, char* msg, ...);
|
||||||
void dump_connection(struct connection *cnx);
|
void dump_connection(struct connection *cnx);
|
||||||
int resolve_split_name(struct addrinfo **out, const char* hostname, const char* port);
|
int resolve_split_name(struct addrinfo **out, char* hostname, char* port);
|
||||||
|
|
||||||
int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list);
|
int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list);
|
||||||
|
|
||||||
@ -123,6 +123,7 @@ int flush_deferred(struct queue *q);
|
|||||||
|
|
||||||
extern int probing_timeout, verbose, inetd, foreground,
|
extern int probing_timeout, verbose, inetd, foreground,
|
||||||
background, transparent, numeric;
|
background, transparent, numeric;
|
||||||
|
extern struct config_item cfg;
|
||||||
extern struct sockaddr_storage addr_ssl, addr_ssh, addr_openvpn;
|
extern struct sockaddr_storage addr_ssl, addr_ssh, addr_openvpn;
|
||||||
extern struct addrinfo *addr_listen;
|
extern struct addrinfo *addr_listen;
|
||||||
extern const char* USAGE_STRING;
|
extern const char* USAGE_STRING;
|
||||||
|
@ -53,6 +53,8 @@ const char* server_type = "echsrv"; /* keep setup_syslog happy */
|
|||||||
char* prefix = "";
|
char* prefix = "";
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
|
int verbose, numeric;
|
||||||
|
|
||||||
void parse_cmdline(int argc, char* argv[])
|
void parse_cmdline(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
@ -66,7 +66,10 @@ listen:
|
|||||||
|
|
||||||
protocols:
|
protocols:
|
||||||
(
|
(
|
||||||
{ name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; keepalive: true; fork: true; },
|
{ name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; keepalive: true; fork: true;
|
||||||
|
listen: ( { host: "hello"; port: "xmpp" }, { host: "world";
|
||||||
|
port: "dns" } ),
|
||||||
|
},
|
||||||
{ name: "http"; host: "localhost"; port: "80"; },
|
{ name: "http"; host: "localhost"; port: "80"; },
|
||||||
|
|
||||||
# match BOTH ALPN/SNI
|
# match BOTH ALPN/SNI
|
||||||
|
129
probe.c
129
probe.c
@ -33,36 +33,43 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int is_ssh_protocol(const char *p, int len, struct proto*);
|
static int is_ssh_protocol(const char *p, int len, struct config_protocols_item*);
|
||||||
static int is_openvpn_protocol(const char *p, int len, struct proto*);
|
static int is_openvpn_protocol(const char *p, int len, struct config_protocols_item*);
|
||||||
static int is_tinc_protocol(const char *p, int len, struct proto*);
|
static int is_tinc_protocol(const char *p, int len, struct config_protocols_item*);
|
||||||
static int is_xmpp_protocol(const char *p, int len, struct proto*);
|
static int is_xmpp_protocol(const char *p, int len, struct config_protocols_item*);
|
||||||
static int is_http_protocol(const char *p, int len, struct proto*);
|
static int is_http_protocol(const char *p, int len, struct config_protocols_item*);
|
||||||
static int is_tls_protocol(const char *p, int len, struct proto*);
|
static int is_tls_protocol(const char *p, int len, struct config_protocols_item*);
|
||||||
static int is_adb_protocol(const char *p, int len, struct proto*);
|
static int is_adb_protocol(const char *p, int len, struct config_protocols_item*);
|
||||||
static int is_socks5_protocol(const char *p, int len, struct proto*);
|
static int is_socks5_protocol(const char *p, int len, struct config_protocols_item*);
|
||||||
static int is_true(const char *p, int len, struct proto* proto) { return 1; }
|
static int is_true(const char *p, int len, struct config_protocols_item* proto) { return 1; }
|
||||||
|
|
||||||
|
struct protocol_probe_desc {
|
||||||
|
const char* name;
|
||||||
|
T_PROBE* probe;
|
||||||
|
};
|
||||||
|
|
||||||
/* Table of protocols that have a built-in probe
|
/* Table of protocols that have a built-in probe
|
||||||
*/
|
*/
|
||||||
static struct proto builtins[] = {
|
static struct protocol_probe_desc builtins[] = {
|
||||||
/* description service saddr log_level keepalive fork probe */
|
/* description probe */
|
||||||
{ "ssh", "sshd", NULL, 1, 0, 1, is_ssh_protocol},
|
{ "ssh", is_ssh_protocol},
|
||||||
{ "openvpn", NULL, NULL, 1, 0, 1, is_openvpn_protocol },
|
{ "openvpn", is_openvpn_protocol },
|
||||||
{ "tinc", NULL, NULL, 1, 0, 1, is_tinc_protocol },
|
{ "tinc", is_tinc_protocol },
|
||||||
{ "xmpp", NULL, NULL, 1, 0, 0, is_xmpp_protocol },
|
{ "xmpp", is_xmpp_protocol },
|
||||||
{ "http", NULL, NULL, 1, 0, 0, is_http_protocol },
|
{ "http", is_http_protocol },
|
||||||
{ "tls", NULL, NULL, 1, 0, 0, is_tls_protocol },
|
{ "tls", is_tls_protocol },
|
||||||
{ "adb", NULL, NULL, 1, 0, 0, is_adb_protocol },
|
{ "ssl", is_tls_protocol },
|
||||||
{ "socks5", NULL, NULL, 1, 0, 0, is_socks5_protocol },
|
{ "adb", is_adb_protocol },
|
||||||
{ "anyprot", NULL, NULL, 1, 0, 0, is_true }
|
{ "socks5", is_socks5_protocol },
|
||||||
|
{ "anyprot", is_true }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct proto *protocols;
|
static struct config_protocols_item *protocols;
|
||||||
static char* on_timeout = "ssh";
|
static char* on_timeout = "ssh";
|
||||||
|
|
||||||
struct proto* get_builtins(void) {
|
/* TODO I think this has to go */
|
||||||
return builtins;
|
struct config_protocols_item* get_builtins(void) {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_num_builtins(void) {
|
int get_num_builtins(void) {
|
||||||
@ -79,23 +86,27 @@ void set_ontimeout(const char* name)
|
|||||||
/* Returns the protocol to connect to in case of timeout;
|
/* Returns the protocol to connect to in case of timeout;
|
||||||
* if not found, return the first protocol specified
|
* if not found, return the first protocol specified
|
||||||
*/
|
*/
|
||||||
struct proto* timeout_protocol(void)
|
struct config_protocols_item* timeout_protocol(void)
|
||||||
{
|
{
|
||||||
struct proto* p = get_first_protocol();
|
int i;
|
||||||
for (; p && strcmp(p->description, on_timeout); p = p->next);
|
for (i = 0; i < cfg.protocols_len; i++) {
|
||||||
if (p) return p;
|
printf("prot %d:%s vs %s\n",i, cfg.protocols[i].name, on_timeout);
|
||||||
|
if (!strcmp(cfg.protocols[i].name, on_timeout)) return &cfg.protocols[i];
|
||||||
|
}
|
||||||
return get_first_protocol();
|
return get_first_protocol();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns the first protocol (caller can then follow the *next pointers) */
|
/* returns the first protocol (caller can then follow the *next pointers) */
|
||||||
struct proto* get_first_protocol(void)
|
struct config_protocols_item* get_first_protocol(void)
|
||||||
{
|
{
|
||||||
return protocols;
|
return protocols;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_protocol_list(struct proto* prots)
|
void set_protocol_list(struct config_protocols_item* prots)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
protocols = prots;
|
protocols = prots;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* From http://grapsus.net/blog/post/Hexadecimal-dump-in-C */
|
/* From http://grapsus.net/blog/post/Hexadecimal-dump-in-C */
|
||||||
@ -132,7 +143,7 @@ void hexdump(const char *mem, unsigned int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Is the buffer the beginning of an SSH connection? */
|
/* Is the buffer the beginning of an SSH connection? */
|
||||||
static int is_ssh_protocol(const char *p, int len, struct proto *proto)
|
static int is_ssh_protocol(const char *p, int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
if (len < 4)
|
if (len < 4)
|
||||||
return PROBE_AGAIN;
|
return PROBE_AGAIN;
|
||||||
@ -150,7 +161,7 @@ static int is_ssh_protocol(const char *p, int len, struct proto *proto)
|
|||||||
* http://www.fengnet.com/book/vpns%20illustrated%20tunnels%20%20vpnsand%20ipsec/ch08lev1sec5.html
|
* http://www.fengnet.com/book/vpns%20illustrated%20tunnels%20%20vpnsand%20ipsec/ch08lev1sec5.html
|
||||||
* and OpenVPN ssl.c, ssl.h and options.c
|
* and OpenVPN ssl.c, ssl.h and options.c
|
||||||
*/
|
*/
|
||||||
static int is_openvpn_protocol (const char*p,int len, struct proto *proto)
|
static int is_openvpn_protocol (const char*p,int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
int packet_len;
|
int packet_len;
|
||||||
|
|
||||||
@ -165,7 +176,7 @@ static int is_openvpn_protocol (const char*p,int len, struct proto *proto)
|
|||||||
* Protocol is documented here: http://www.tinc-vpn.org/documentation/tinc.pdf
|
* Protocol is documented here: http://www.tinc-vpn.org/documentation/tinc.pdf
|
||||||
* First connection starts with "0 " in 1.0.15)
|
* First connection starts with "0 " in 1.0.15)
|
||||||
* */
|
* */
|
||||||
static int is_tinc_protocol( const char *p, int len, struct proto *proto)
|
static int is_tinc_protocol( const char *p, int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
if (len < 2)
|
if (len < 2)
|
||||||
return PROBE_AGAIN;
|
return PROBE_AGAIN;
|
||||||
@ -177,7 +188,7 @@ static int is_tinc_protocol( const char *p, int len, struct proto *proto)
|
|||||||
* (Protocol is documented (http://tools.ietf.org/html/rfc6120) but for lazy
|
* (Protocol is documented (http://tools.ietf.org/html/rfc6120) but for lazy
|
||||||
* clients, just checking first frame containing "jabber" in xml entity)
|
* clients, just checking first frame containing "jabber" in xml entity)
|
||||||
* */
|
* */
|
||||||
static int is_xmpp_protocol( const char *p, int len, struct proto *proto)
|
static int is_xmpp_protocol( const char *p, int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
if (memmem(p, len, "jabber", 6))
|
if (memmem(p, len, "jabber", 6))
|
||||||
return PROBE_MATCH;
|
return PROBE_MATCH;
|
||||||
@ -200,7 +211,7 @@ static int probe_http_method(const char *p, int len, const char *opt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Is the buffer the beginning of an HTTP connection? */
|
/* Is the buffer the beginning of an HTTP connection? */
|
||||||
static int is_http_protocol(const char *p, int len, struct proto *proto)
|
static int is_http_protocol(const char *p, int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
/* If it's got HTTP in the request (HTTP/1.1) then it's HTTP */
|
/* If it's got HTTP in the request (HTTP/1.1) then it's HTTP */
|
||||||
@ -226,7 +237,7 @@ static int is_http_protocol(const char *p, int len, struct proto *proto)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Says if it's TLS, optionally with SNI and ALPN lists in proto->data */
|
/* Says if it's TLS, optionally with SNI and ALPN lists in proto->data */
|
||||||
static int is_tls_protocol(const char *p, int len, struct proto *proto)
|
static int is_tls_protocol(const char *p, int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
switch (parse_tls_header(proto->data, p, len)) {
|
switch (parse_tls_header(proto->data, p, len)) {
|
||||||
case TLS_MATCH: return PROBE_MATCH;
|
case TLS_MATCH: return PROBE_MATCH;
|
||||||
@ -246,7 +257,7 @@ static int probe_adb_cnxn_message(const char *p)
|
|||||||
return !memcmp(&p[0], "CNXN", 4) && !memcmp(&p[24], "host:", 5);
|
return !memcmp(&p[0], "CNXN", 4) && !memcmp(&p[24], "host:", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_adb_protocol(const char *p, int len, struct proto *proto)
|
static int is_adb_protocol(const char *p, int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
/* amessage.data_length is not being checked, under the assumption that
|
/* amessage.data_length is not being checked, under the assumption that
|
||||||
* a packet >= 30 bytes will have "something" in the payload field.
|
* a packet >= 30 bytes will have "something" in the payload field.
|
||||||
@ -285,7 +296,7 @@ static int is_adb_protocol(const char *p, int len, struct proto *proto)
|
|||||||
return probe_adb_cnxn_message(&p[sizeof(empty_message)]);
|
return probe_adb_cnxn_message(&p[sizeof(empty_message)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_socks5_protocol(const char *p_in, int len, struct proto *proto)
|
static int is_socks5_protocol(const char *p_in, int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
unsigned char* p = (unsigned char*)p_in;
|
unsigned char* p = (unsigned char*)p_in;
|
||||||
int i;
|
int i;
|
||||||
@ -318,7 +329,7 @@ static int is_socks5_protocol(const char *p_in, int len, struct proto *proto)
|
|||||||
return PROBE_MATCH;
|
return PROBE_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int regex_probe(const char *p, int len, struct proto *proto)
|
static int regex_probe(const char *p, int len, struct config_protocols_item* proto)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_REGEX
|
#ifdef ENABLE_REGEX
|
||||||
regex_t **probe = proto->data;
|
regex_t **probe = proto->data;
|
||||||
@ -344,8 +355,8 @@ static int regex_probe(const char *p, int len, struct proto *proto)
|
|||||||
int probe_client_protocol(struct connection *cnx)
|
int probe_client_protocol(struct connection *cnx)
|
||||||
{
|
{
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
struct proto *p, *last_p = cnx->proto;
|
struct config_protocols_item* p, *last_p = cnx->proto;
|
||||||
int n, res, again = 0;
|
int i, n, res, again = 0;
|
||||||
|
|
||||||
n = read(cnx->q[0].fd, buffer, sizeof(buffer));
|
n = read(cnx->q[0].fd, buffer, sizeof(buffer));
|
||||||
/* It's possible that read() returns an error, e.g. if the client
|
/* It's possible that read() returns an error, e.g. if the client
|
||||||
@ -355,26 +366,26 @@ int probe_client_protocol(struct connection *cnx)
|
|||||||
* connection will just fail later normally). */
|
* connection will just fail later normally). */
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
if (verbose > 1) {
|
if (cfg.verbose > 1) {
|
||||||
fprintf(stderr, "hexdump of incoming packet:\n");
|
fprintf(stderr, "hexdump of incoming packet:\n");
|
||||||
hexdump(buffer, n);
|
hexdump(buffer, n);
|
||||||
}
|
}
|
||||||
defer_write(&cnx->q[1], buffer, n);
|
defer_write(&cnx->q[1], buffer, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p = cnx->proto; p; p = p->next) {
|
for (i = 0; i < cfg.protocols_len; i++) {
|
||||||
char* probe_str[3] = {"PROBE_NEXT", "PROBE_MATCH", "PROBE_AGAIN"};
|
char* probe_str[3] = {"PROBE_NEXT", "PROBE_MATCH", "PROBE_AGAIN"};
|
||||||
|
p = &cfg.protocols[i];
|
||||||
|
|
||||||
if (! p->probe) continue;
|
if (! p->probe) continue;
|
||||||
|
|
||||||
/* Don't probe last protocol if it is anyprot (and store last protocol) */
|
/* Don't probe last protocol if it is anyprot (and store last protocol) */
|
||||||
if (! p->next) {
|
if ((i == cfg.protocols_len - 1) && (!strcmp(p->name, "anyprot")))
|
||||||
last_p = p;
|
|
||||||
if (!strcmp(p->description, "anyprot"))
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
|
if (cfg.verbose) fprintf(stderr, "probing for %s\n", p->name);
|
||||||
res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p);
|
res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p);
|
||||||
if (verbose) fprintf(stderr, "probing for %s: %s\n", p->description, probe_str[res]);
|
if (cfg.verbose) fprintf(stderr, "probed for %s: %s\n", p->name, probe_str[res]);
|
||||||
|
|
||||||
if (res == PROBE_MATCH) {
|
if (res == PROBE_MATCH) {
|
||||||
cnx->proto = p;
|
cnx->proto = p;
|
||||||
@ -387,31 +398,21 @@ int probe_client_protocol(struct connection *cnx)
|
|||||||
return PROBE_AGAIN;
|
return PROBE_AGAIN;
|
||||||
|
|
||||||
/* Everything failed: match the last one */
|
/* Everything failed: match the last one */
|
||||||
cnx->proto = last_p;
|
cnx->proto = &cfg.protocols[cfg.protocols_len-1];
|
||||||
return PROBE_MATCH;
|
return PROBE_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the structure for specified protocol or NULL if not found */
|
|
||||||
static struct proto* get_protocol(const char* description)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(builtins); i++) {
|
|
||||||
if (!strcmp(builtins[i].description, description)) {
|
|
||||||
return &builtins[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the probe for specified protocol:
|
/* Returns the probe for specified protocol:
|
||||||
* parameter is the description in builtins[], or "regex"
|
* parameter is the description in builtins[], or "regex"
|
||||||
* */
|
* */
|
||||||
T_PROBE* get_probe(const char* description) {
|
T_PROBE* get_probe(const char* description) {
|
||||||
struct proto* p = get_protocol(description);
|
int i;
|
||||||
|
|
||||||
if (p)
|
for (i = 0; i < ARRAY_SIZE(builtins); i++) {
|
||||||
return p->probe;
|
if (!strcmp(builtins[i].name, description)) {
|
||||||
|
return builtins[i].probe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Special case of "regex" probe (we don't want to set it in builtins
|
/* Special case of "regex" probe (we don't want to set it in builtins
|
||||||
* because builtins is also used to build the command-line options and
|
* because builtins is also used to build the command-line options and
|
||||||
|
16
probe.h
16
probe.h
@ -12,10 +12,13 @@ typedef enum {
|
|||||||
PROBE_AGAIN, /* Not enough data for this probe, try again with more data */
|
PROBE_AGAIN, /* Not enough data for this probe, try again with more data */
|
||||||
} probe_result;
|
} probe_result;
|
||||||
|
|
||||||
struct proto;
|
struct config_protocols_item;
|
||||||
typedef int T_PROBE(const char*, int, struct proto*);
|
typedef int T_PROBE(const char*, int, struct config_protocols_item*);
|
||||||
|
|
||||||
|
#include "sslh-conf.h"
|
||||||
|
|
||||||
/* For each protocol we need: */
|
/* For each protocol we need: */
|
||||||
|
#if 0
|
||||||
struct proto {
|
struct proto {
|
||||||
const char* description; /* a string that says what it is (for logging and command-line parsing) */
|
const char* description; /* a string that says what it is (for logging and command-line parsing) */
|
||||||
const char* service; /* service name to do libwrap checks */
|
const char* service; /* service name to do libwrap checks */
|
||||||
@ -33,9 +36,10 @@ struct proto {
|
|||||||
void* data;
|
void* data;
|
||||||
struct proto *next; /* pointer to next protocol in list, NULL if last */
|
struct proto *next; /* pointer to next protocol in list, NULL if last */
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Returns a pointer to the array of builtin protocols */
|
/* Returns a pointer to the array of builtin protocols */
|
||||||
struct proto * get_builtins(void);
|
struct config_protocols_item* get_builtins(void);
|
||||||
|
|
||||||
/* Returns the number of builtin protocols */
|
/* Returns the number of builtin protocols */
|
||||||
int get_num_builtins(void);
|
int get_num_builtins(void);
|
||||||
@ -44,10 +48,10 @@ int get_num_builtins(void);
|
|||||||
T_PROBE* get_probe(const char* description);
|
T_PROBE* get_probe(const char* description);
|
||||||
|
|
||||||
/* Returns the head of the configured protocols */
|
/* Returns the head of the configured protocols */
|
||||||
struct proto* get_first_protocol(void);
|
struct config_protocols_item* get_first_protocol(void);
|
||||||
|
|
||||||
/* Set the list of configured protocols */
|
/* Set the list of configured protocols */
|
||||||
void set_protocol_list(struct proto*);
|
void set_protocol_list(struct config_protocols_item*);
|
||||||
|
|
||||||
/* probe_client_protocol
|
/* probe_client_protocol
|
||||||
*
|
*
|
||||||
@ -65,7 +69,7 @@ void set_ontimeout(const char* name);
|
|||||||
*
|
*
|
||||||
* Returns the protocol to connect to in case of timeout
|
* Returns the protocol to connect to in case of timeout
|
||||||
*/
|
*/
|
||||||
struct proto* timeout_protocol(void);
|
struct config_protocols_item* timeout_protocol(void);
|
||||||
|
|
||||||
void hexdump(const char*, unsigned int);
|
void hexdump(const char*, unsigned int);
|
||||||
|
|
||||||
|
77
sslh-conf.c
77
sslh-conf.c
@ -1,8 +1,9 @@
|
|||||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct)
|
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct)
|
||||||
* on Thu Nov 22 17:16:04 2018. */
|
* on Wed Nov 28 23:38:56 2018. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -10,10 +11,11 @@
|
|||||||
|
|
||||||
static int config_protocols_parser(
|
static int config_protocols_parser(
|
||||||
config_setting_t* cfg,
|
config_setting_t* cfg,
|
||||||
struct config_protocols_items* config_protocols,
|
struct config_protocols_item* config_protocols,
|
||||||
const char** errmsg)
|
const char** errmsg)
|
||||||
{
|
{
|
||||||
config_setting_t* setting;
|
config_setting_t* setting;
|
||||||
|
char* tmp;
|
||||||
*errmsg = NULL;
|
*errmsg = NULL;
|
||||||
|
|
||||||
if (config_setting_lookup(cfg, "name")) {
|
if (config_setting_lookup(cfg, "name")) {
|
||||||
@ -34,6 +36,11 @@ static int config_protocols_parser(
|
|||||||
*errmsg = "Mandatory option \"host\" is missing";
|
*errmsg = "Mandatory option \"host\" is missing";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (asprintf(&tmp, "%s", config_protocols->host) == -1) {
|
||||||
|
*errmsg = "asprintf: cannot allocate memory";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
config_protocols->host = tmp;
|
||||||
if (config_setting_lookup(cfg, "port")) {
|
if (config_setting_lookup(cfg, "port")) {
|
||||||
if (config_setting_lookup_string(cfg, "port", &config_protocols->port) == CONFIG_FALSE) {
|
if (config_setting_lookup_string(cfg, "port", &config_protocols->port) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option \"port\" failed";
|
*errmsg = "Parsing of option \"port\" failed";
|
||||||
@ -43,10 +50,15 @@ static int config_protocols_parser(
|
|||||||
*errmsg = "Mandatory option \"port\" is missing";
|
*errmsg = "Mandatory option \"port\" is missing";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (asprintf(&tmp, "%s", config_protocols->port) == -1) {
|
||||||
|
*errmsg = "asprintf: cannot allocate memory";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
config_protocols->port = tmp;
|
||||||
config_protocols->service = NULL;
|
config_protocols->service = NULL;
|
||||||
if (config_setting_lookup(cfg, "service")) {
|
if (config_setting_lookup(cfg, "service")) {
|
||||||
if (config_setting_lookup_string(cfg, "service", &config_protocols->service) == CONFIG_FALSE) {
|
if (config_setting_lookup_string(cfg, "service", &config_protocols->service) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option service failed";
|
*errmsg = "Parsing of option \"service\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
config_protocols->service_is_present = 1;
|
config_protocols->service_is_present = 1;
|
||||||
@ -56,21 +68,21 @@ static int config_protocols_parser(
|
|||||||
config_protocols->fork = 0;
|
config_protocols->fork = 0;
|
||||||
if (config_setting_lookup(cfg, "fork")) {
|
if (config_setting_lookup(cfg, "fork")) {
|
||||||
if (config_setting_lookup_bool(cfg, "fork", &config_protocols->fork) == CONFIG_FALSE) {
|
if (config_setting_lookup_bool(cfg, "fork", &config_protocols->fork) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option fork failed";
|
*errmsg = "Parsing of option \"fork\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config_protocols->log_level = 1;
|
config_protocols->log_level = 1;
|
||||||
if (config_setting_lookup(cfg, "log_level")) {
|
if (config_setting_lookup(cfg, "log_level")) {
|
||||||
if (config_setting_lookup_int(cfg, "log_level", &config_protocols->log_level) == CONFIG_FALSE) {
|
if (config_setting_lookup_int(cfg, "log_level", &config_protocols->log_level) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option log_level failed";
|
*errmsg = "Parsing of option \"log_level\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config_protocols->keepalive = 0;
|
config_protocols->keepalive = 0;
|
||||||
if (config_setting_lookup(cfg, "keepalive")) {
|
if (config_setting_lookup(cfg, "keepalive")) {
|
||||||
if (config_setting_lookup_bool(cfg, "keepalive", &config_protocols->keepalive) == CONFIG_FALSE) {
|
if (config_setting_lookup_bool(cfg, "keepalive", &config_protocols->keepalive) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option keepalive failed";
|
*errmsg = "Parsing of option \"keepalive\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
@ -112,10 +124,11 @@ static int config_protocols_parser(
|
|||||||
|
|
||||||
static int config_listen_parser(
|
static int config_listen_parser(
|
||||||
config_setting_t* cfg,
|
config_setting_t* cfg,
|
||||||
struct config_listen_items* config_listen,
|
struct config_listen_item* config_listen,
|
||||||
const char** errmsg)
|
const char** errmsg)
|
||||||
{
|
{
|
||||||
config_setting_t* setting;
|
config_setting_t* setting;
|
||||||
|
char* tmp;
|
||||||
*errmsg = NULL;
|
*errmsg = NULL;
|
||||||
|
|
||||||
if (config_setting_lookup(cfg, "host")) {
|
if (config_setting_lookup(cfg, "host")) {
|
||||||
@ -127,6 +140,11 @@ static int config_listen_parser(
|
|||||||
*errmsg = "Mandatory option \"host\" is missing";
|
*errmsg = "Mandatory option \"host\" is missing";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (asprintf(&tmp, "%s", config_listen->host) == -1) {
|
||||||
|
*errmsg = "asprintf: cannot allocate memory";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
config_listen->host = tmp;
|
||||||
if (config_setting_lookup(cfg, "port")) {
|
if (config_setting_lookup(cfg, "port")) {
|
||||||
if (config_setting_lookup_string(cfg, "port", &config_listen->port) == CONFIG_FALSE) {
|
if (config_setting_lookup_string(cfg, "port", &config_listen->port) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option \"port\" failed";
|
*errmsg = "Parsing of option \"port\" failed";
|
||||||
@ -136,10 +154,15 @@ static int config_listen_parser(
|
|||||||
*errmsg = "Mandatory option \"port\" is missing";
|
*errmsg = "Mandatory option \"port\" is missing";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (asprintf(&tmp, "%s", config_listen->port) == -1) {
|
||||||
|
*errmsg = "asprintf: cannot allocate memory";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
config_listen->port = tmp;
|
||||||
config_listen->keepalive = 0;
|
config_listen->keepalive = 0;
|
||||||
if (config_setting_lookup(cfg, "keepalive")) {
|
if (config_setting_lookup(cfg, "keepalive")) {
|
||||||
if (config_setting_lookup_bool(cfg, "keepalive", &config_listen->keepalive) == CONFIG_FALSE) {
|
if (config_setting_lookup_bool(cfg, "keepalive", &config_listen->keepalive) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option keepalive failed";
|
*errmsg = "Parsing of option \"keepalive\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
@ -148,58 +171,59 @@ static int config_listen_parser(
|
|||||||
|
|
||||||
int config_parser(
|
int config_parser(
|
||||||
config_setting_t* cfg,
|
config_setting_t* cfg,
|
||||||
struct config_items* config,
|
struct config_item* config,
|
||||||
const char** errmsg)
|
const char** errmsg)
|
||||||
{
|
{
|
||||||
config_setting_t* setting;
|
config_setting_t* setting;
|
||||||
|
char* tmp;
|
||||||
*errmsg = NULL;
|
*errmsg = NULL;
|
||||||
|
|
||||||
config->verbose = 0;
|
config->verbose = 0;
|
||||||
if (config_setting_lookup(cfg, "verbose")) {
|
if (config_setting_lookup(cfg, "verbose")) {
|
||||||
if (config_setting_lookup_bool(cfg, "verbose", &config->verbose) == CONFIG_FALSE) {
|
if (config_setting_lookup_int(cfg, "verbose", &config->verbose) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option verbose failed";
|
*errmsg = "Parsing of option \"verbose\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config->foreground = 0;
|
config->foreground = 0;
|
||||||
if (config_setting_lookup(cfg, "foreground")) {
|
if (config_setting_lookup(cfg, "foreground")) {
|
||||||
if (config_setting_lookup_bool(cfg, "foreground", &config->foreground) == CONFIG_FALSE) {
|
if (config_setting_lookup_bool(cfg, "foreground", &config->foreground) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option foreground failed";
|
*errmsg = "Parsing of option \"foreground\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config->inetd = 0;
|
config->inetd = 0;
|
||||||
if (config_setting_lookup(cfg, "inetd")) {
|
if (config_setting_lookup(cfg, "inetd")) {
|
||||||
if (config_setting_lookup_bool(cfg, "inetd", &config->inetd) == CONFIG_FALSE) {
|
if (config_setting_lookup_bool(cfg, "inetd", &config->inetd) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option inetd failed";
|
*errmsg = "Parsing of option \"inetd\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config->numeric = 0;
|
config->numeric = 0;
|
||||||
if (config_setting_lookup(cfg, "numeric")) {
|
if (config_setting_lookup(cfg, "numeric")) {
|
||||||
if (config_setting_lookup_bool(cfg, "numeric", &config->numeric) == CONFIG_FALSE) {
|
if (config_setting_lookup_bool(cfg, "numeric", &config->numeric) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option numeric failed";
|
*errmsg = "Parsing of option \"numeric\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config->transparent = 0;
|
config->transparent = 0;
|
||||||
if (config_setting_lookup(cfg, "transparent")) {
|
if (config_setting_lookup(cfg, "transparent")) {
|
||||||
if (config_setting_lookup_bool(cfg, "transparent", &config->transparent) == CONFIG_FALSE) {
|
if (config_setting_lookup_bool(cfg, "transparent", &config->transparent) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option transparent failed";
|
*errmsg = "Parsing of option \"transparent\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config->timeout = 2;
|
config->timeout = 2;
|
||||||
if (config_setting_lookup(cfg, "timeout")) {
|
if (config_setting_lookup(cfg, "timeout")) {
|
||||||
if (config_setting_lookup_int(cfg, "timeout", &config->timeout) == CONFIG_FALSE) {
|
if (config_setting_lookup_int(cfg, "timeout", &config->timeout) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option timeout failed";
|
*errmsg = "Parsing of option \"timeout\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config->user = NULL;
|
config->user = NULL;
|
||||||
if (config_setting_lookup(cfg, "user")) {
|
if (config_setting_lookup(cfg, "user")) {
|
||||||
if (config_setting_lookup_string(cfg, "user", &config->user) == CONFIG_FALSE) {
|
if (config_setting_lookup_string(cfg, "user", &config->user) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option user failed";
|
*errmsg = "Parsing of option \"user\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
config->user_is_present = 1;
|
config->user_is_present = 1;
|
||||||
@ -209,33 +233,34 @@ int config_parser(
|
|||||||
config->pidfile = NULL;
|
config->pidfile = NULL;
|
||||||
if (config_setting_lookup(cfg, "pidfile")) {
|
if (config_setting_lookup(cfg, "pidfile")) {
|
||||||
if (config_setting_lookup_string(cfg, "pidfile", &config->pidfile) == CONFIG_FALSE) {
|
if (config_setting_lookup_string(cfg, "pidfile", &config->pidfile) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option pidfile failed";
|
*errmsg = "Parsing of option \"pidfile\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
config->pidfile_is_present = 1;
|
config->pidfile_is_present = 1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
config->chroot = NULL;
|
||||||
if (config_setting_lookup(cfg, "chroot")) {
|
if (config_setting_lookup(cfg, "chroot")) {
|
||||||
if (config_setting_lookup_string(cfg, "chroot", &config->chroot) == CONFIG_FALSE) {
|
if (config_setting_lookup_string(cfg, "chroot", &config->chroot) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option \"chroot\" failed";
|
*errmsg = "Parsing of option \"chroot\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
*errmsg = "Mandatory option \"chroot\" is missing";
|
config->chroot_is_present = 1;
|
||||||
return 0;
|
}
|
||||||
|
;
|
||||||
}
|
}
|
||||||
config->syslog_facility = "auth";
|
config->syslog_facility = "auth";
|
||||||
if (config_setting_lookup(cfg, "syslog_facility")) {
|
if (config_setting_lookup(cfg, "syslog_facility")) {
|
||||||
if (config_setting_lookup_string(cfg, "syslog_facility", &config->syslog_facility) == CONFIG_FALSE) {
|
if (config_setting_lookup_string(cfg, "syslog_facility", &config->syslog_facility) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option syslog_facility failed";
|
*errmsg = "Parsing of option \"syslog_facility\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
config->on_timeout = "ssh";
|
config->on_timeout = "ssh";
|
||||||
if (config_setting_lookup(cfg, "on_timeout")) {
|
if (config_setting_lookup(cfg, "on_timeout")) {
|
||||||
if (config_setting_lookup_string(cfg, "on_timeout", &config->on_timeout) == CONFIG_FALSE) {
|
if (config_setting_lookup_string(cfg, "on_timeout", &config->on_timeout) == CONFIG_FALSE) {
|
||||||
*errmsg = "Parsing of option on_timeout failed";
|
*errmsg = "Parsing of option \"on_timeout\" failed";
|
||||||
return 0;
|
return 0;
|
||||||
} ;
|
} ;
|
||||||
}
|
}
|
||||||
@ -276,7 +301,7 @@ static void indent(int depth)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void config_protocols_print(
|
static void config_protocols_print(
|
||||||
struct config_protocols_items* config_protocols,
|
struct config_protocols_item* config_protocols,
|
||||||
int depth)
|
int depth)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -316,7 +341,7 @@ static void config_protocols_print(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void config_listen_print(
|
static void config_listen_print(
|
||||||
struct config_listen_items* config_listen,
|
struct config_listen_item* config_listen,
|
||||||
int depth)
|
int depth)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -330,7 +355,7 @@ static void config_listen_print(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void config_print(
|
void config_print(
|
||||||
struct config_items* config,
|
struct config_item* config,
|
||||||
int depth)
|
int depth)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
48
sslh-conf.h
48
sslh-conf.h
@ -1,10 +1,26 @@
|
|||||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct)
|
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct)
|
||||||
* on Thu Nov 22 17:16:04 2018. */
|
* on Wed Nov 28 23:38:56 2018. */
|
||||||
|
|
||||||
struct config_protocols_items {
|
|
||||||
|
#ifndef C2S_CONFIG_H
|
||||||
|
#define C2S_CONFIG_H
|
||||||
|
#include <libconfig.h>
|
||||||
|
|
||||||
|
#include "probe.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
struct config_listen_item {
|
||||||
|
char* host;
|
||||||
|
char* port;
|
||||||
|
int keepalive;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_protocols_item {
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* host;
|
char* host;
|
||||||
const char* port;
|
char* port;
|
||||||
int service_is_present;
|
int service_is_present;
|
||||||
const char* service;
|
const char* service;
|
||||||
int fork;
|
int fork;
|
||||||
@ -16,17 +32,12 @@ struct config_protocols_items {
|
|||||||
const char** alpn_protocols;
|
const char** alpn_protocols;
|
||||||
int regex_patterns_len;
|
int regex_patterns_len;
|
||||||
const char** regex_patterns;
|
const char** regex_patterns;
|
||||||
|
T_PROBE* probe;
|
||||||
|
struct addrinfo* saddr;
|
||||||
|
void* data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct config_item {
|
||||||
struct config_listen_items {
|
|
||||||
const char* host;
|
|
||||||
const char* port;
|
|
||||||
int keepalive;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct config_items {
|
|
||||||
int verbose;
|
int verbose;
|
||||||
int foreground;
|
int foreground;
|
||||||
int inetd;
|
int inetd;
|
||||||
@ -37,20 +48,23 @@ struct config_items {
|
|||||||
const char* user;
|
const char* user;
|
||||||
int pidfile_is_present;
|
int pidfile_is_present;
|
||||||
const char* pidfile;
|
const char* pidfile;
|
||||||
|
int chroot_is_present;
|
||||||
const char* chroot;
|
const char* chroot;
|
||||||
const char* syslog_facility;
|
const char* syslog_facility;
|
||||||
const char* on_timeout;
|
const char* on_timeout;
|
||||||
int listen_len;
|
int listen_len;
|
||||||
struct config_listen_items* listen;
|
struct config_listen_item* listen;
|
||||||
int protocols_len;
|
int protocols_len;
|
||||||
struct config_protocols_items* protocols;
|
struct config_protocols_item* protocols;
|
||||||
};
|
};
|
||||||
|
|
||||||
int config_parser(
|
int config_parser(
|
||||||
config_setting_t* cfg,
|
config_setting_t* cfg,
|
||||||
struct config_items* config,
|
struct config_item* config,
|
||||||
const char** errmsg);
|
const char** errmsg);
|
||||||
|
|
||||||
void config_print(
|
void config_print(
|
||||||
struct config_items *config,
|
struct config_item *config,
|
||||||
int depth);
|
int depth);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
12
sslh-fork.c
12
sslh-fork.c
@ -54,7 +54,7 @@ int shovel(struct connection *cnx)
|
|||||||
if (FD_ISSET(cnx->q[i].fd, &fds)) {
|
if (FD_ISSET(cnx->q[i].fd, &fds)) {
|
||||||
res = fd2fd(&cnx->q[1-i], &cnx->q[i]);
|
res = fd2fd(&cnx->q[1-i], &cnx->q[i]);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "%s %s", i ? "client" : "server", "socket closed\n");
|
fprintf(stderr, "%s %s", i ? "client" : "server", "socket closed\n");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ void start_shoveler(int in_socket)
|
|||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(in_socket, &fds);
|
FD_SET(in_socket, &fds);
|
||||||
memset(&tv, 0, sizeof(tv));
|
memset(&tv, 0, sizeof(tv));
|
||||||
tv.tv_sec = probing_timeout;
|
tv.tv_sec = cfg.timeout;
|
||||||
|
|
||||||
while (res == PROBE_AGAIN) {
|
while (res == PROBE_AGAIN) {
|
||||||
/* POSIX does not guarantee that tv will be updated, but the client can
|
/* POSIX does not guarantee that tv will be updated, but the client can
|
||||||
@ -94,8 +94,8 @@ void start_shoveler(int in_socket)
|
|||||||
} else {
|
} else {
|
||||||
/* Timed out: it's necessarily SSH */
|
/* Timed out: it's necessarily SSH */
|
||||||
cnx.proto = timeout_protocol();
|
cnx.proto = timeout_protocol();
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
log_message(LOG_INFO, "timed out, connect to %s\n", cnx.proto->description);
|
log_message(LOG_INFO, "timed out, connect to %s\n", cnx.proto->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ void start_shoveler(int in_socket)
|
|||||||
close(in_socket);
|
close(in_socket);
|
||||||
close(out_socket);
|
close(out_socket);
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "connection closed down\n");
|
fprintf(stderr, "connection closed down\n");
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
@ -161,7 +161,7 @@ void main_loop(int listen_sockets[], int num_addr_listen)
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
in_socket = accept(listen_sockets[i], 0, 0);
|
in_socket = accept(listen_sockets[i], 0, 0);
|
||||||
if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
|
if (cfg.verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
|
||||||
|
|
||||||
switch(fork()) {
|
switch(fork()) {
|
||||||
case -1: log_message(LOG_ERR, "fork failed: err %d: %s\n", errno, strerror(errno));
|
case -1: log_message(LOG_ERR, "fork failed: err %d: %s\n", errno, strerror(errno));
|
||||||
|
193
sslh-main.c
193
sslh-main.c
@ -2,7 +2,7 @@
|
|||||||
# main: processing of config file, command line options and start the main
|
# main: processing of config file, command line options and start the main
|
||||||
# loop.
|
# loop.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2007-2016 Yves Rutschle
|
# Copyright (C) 2007-2018 Yves Rutschle
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it
|
# This program is free software; you can redistribute it
|
||||||
# and/or modify it under the terms of the GNU General Public
|
# and/or modify it under the terms of the GNU General Public
|
||||||
@ -62,6 +62,7 @@ const char* USAGE_STRING =
|
|||||||
/* Constants for options that have no one-character shorthand */
|
/* Constants for options that have no one-character shorthand */
|
||||||
#define OPT_ONTIMEOUT 257
|
#define OPT_ONTIMEOUT 257
|
||||||
|
|
||||||
|
/*
|
||||||
static struct option const_options[] = {
|
static struct option const_options[] = {
|
||||||
{ "inetd", no_argument, &inetd, 1 },
|
{ "inetd", no_argument, &inetd, 1 },
|
||||||
{ "foreground", no_argument, &foreground, 1 },
|
{ "foreground", no_argument, &foreground, 1 },
|
||||||
@ -78,22 +79,25 @@ static struct option const_options[] = {
|
|||||||
{ "listen", required_argument, 0, 'p' },
|
{ "listen", required_argument, 0, 'p' },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
static struct option* all_options;
|
static struct option* all_options;
|
||||||
static struct proto* builtins;
|
#if 0
|
||||||
|
static struct config_protocols_item* builtins;
|
||||||
|
#endif
|
||||||
static const char *optstr = "vt:T:p:VP:C:F::";
|
static const char *optstr = "vt:T:p:VP:C:F::";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void print_usage(void)
|
static void print_usage(void)
|
||||||
{
|
{
|
||||||
struct proto *p;
|
struct config_protocols_item *p;
|
||||||
int i;
|
int i;
|
||||||
int res;
|
int res;
|
||||||
char *prots = "";
|
char *prots = "";
|
||||||
|
|
||||||
p = get_builtins();
|
p = get_builtins();
|
||||||
for (i = 0; i < get_num_builtins(); i++) {
|
for (i = 0; i < get_num_builtins(); i++) {
|
||||||
res = asprintf(&prots, "%s\t[--%s <addr>]\n", prots, p[i].description);
|
res = asprintf(&prots, "%s\t[--%s <addr>]\n", prots, p[i].name);
|
||||||
CHECK_RES_DIE(res, "asprintf");
|
CHECK_RES_DIE(res, "asprintf");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,12 +125,14 @@ static void printsettings(void)
|
|||||||
{
|
{
|
||||||
char buf[NI_MAXHOST];
|
char buf[NI_MAXHOST];
|
||||||
struct addrinfo *a;
|
struct addrinfo *a;
|
||||||
struct proto *p;
|
int i;
|
||||||
|
struct config_protocols_item *p;
|
||||||
|
|
||||||
for (p = get_first_protocol(); p; p = p->next) {
|
for (i = 0; i < cfg.protocols_len; i++ ) {
|
||||||
|
p = &cfg.protocols[i];
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s] [%s]\n",
|
"%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s] [%s]\n",
|
||||||
p->description,
|
p->name,
|
||||||
sprintaddr(buf, sizeof(buf), p->saddr),
|
sprintaddr(buf, sizeof(buf), p->saddr),
|
||||||
p->service,
|
p->service,
|
||||||
p->log_level,
|
p->log_level,
|
||||||
@ -142,8 +148,8 @@ static void printsettings(void)
|
|||||||
sprintaddr(buf, sizeof(buf), a),
|
sprintaddr(buf, sizeof(buf), a),
|
||||||
a->ai_flags & SO_KEEPALIVE ? "keepalive" : "");
|
a->ai_flags & SO_KEEPALIVE ? "keepalive" : "");
|
||||||
}
|
}
|
||||||
fprintf(stderr, "timeout: %d\non-timeout: %s\n", probing_timeout,
|
fprintf(stderr, "timeout: %d\non-timeout: %s\n", cfg.timeout,
|
||||||
timeout_protocol()->description);
|
timeout_protocol()->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -177,6 +183,26 @@ void cmd_ssl_to_tls(int argc, char* argv[])
|
|||||||
* out: newly allocated list of addrinfo to listen to
|
* out: newly allocated list of addrinfo to listen to
|
||||||
*/
|
*/
|
||||||
#ifdef LIBCONFIG
|
#ifdef LIBCONFIG
|
||||||
|
static int config_resolve_listen(struct addrinfo **listen)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < cfg.listen_len; i++) {
|
||||||
|
resolve_split_name(listen, cfg.listen[i].host, cfg.listen[i].port);
|
||||||
|
|
||||||
|
/* getaddrinfo returned a list of addresses corresponding to the
|
||||||
|
* specification; move the pointer to the end of that list before
|
||||||
|
* processing the next specification, while setting flags for
|
||||||
|
* start_listen_sockets() through ai_flags (which is not meant for
|
||||||
|
* that, but is only used as hint in getaddrinfo, so it's OK) */
|
||||||
|
for (; *listen; listen = &((*listen)->ai_next)) {
|
||||||
|
if (cfg.listen[i].keepalive)
|
||||||
|
(*listen)->ai_flags = SO_KEEPALIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static int config_listen(config_t *config, struct addrinfo **listen)
|
static int config_listen(config_t *config, struct addrinfo **listen)
|
||||||
{
|
{
|
||||||
config_setting_t *setting, *addr;
|
config_setting_t *setting, *addr;
|
||||||
@ -216,11 +242,12 @@ static int config_listen(config_t *config, struct addrinfo **listen)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef LIBCONFIG
|
#ifdef LIBCONFIG
|
||||||
static void setup_regex_probe(struct proto *p, config_setting_t* probes)
|
static void setup_regex_probe(struct config_protocols_item *p, config_setting_t* probes)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_REGEX
|
#ifdef ENABLE_REGEX
|
||||||
int num_probes, errsize, i, res;
|
int num_probes, errsize, i, res;
|
||||||
@ -230,7 +257,7 @@ static void setup_regex_probe(struct proto *p, config_setting_t* probes)
|
|||||||
|
|
||||||
num_probes = config_setting_length(probes);
|
num_probes = config_setting_length(probes);
|
||||||
if (!num_probes) {
|
if (!num_probes) {
|
||||||
fprintf(stderr, "%s: no probes specified\n", p->description);
|
fprintf(stderr, "%s: no probes specified\n", p->name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +271,7 @@ static void setup_regex_probe(struct proto *p, config_setting_t* probes)
|
|||||||
CHECK_ALLOC(probe_list[i], "malloc");
|
CHECK_ALLOC(probe_list[i], "malloc");
|
||||||
expr = config_setting_get_string_elem(probes, i);
|
expr = config_setting_get_string_elem(probes, i);
|
||||||
if (expr == NULL) {
|
if (expr == NULL) {
|
||||||
fprintf(stderr, "%s: invalid probe specified\n", p->description);
|
fprintf(stderr, "%s: invalid probe specified\n", p->name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
res = regcomp(probe_list[i], expr, REG_EXTENDED);
|
res = regcomp(probe_list[i], expr, REG_EXTENDED);
|
||||||
@ -265,7 +292,12 @@ static void setup_regex_probe(struct proto *p, config_setting_t* probes)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LIBCONFIG
|
#ifdef LIBCONFIG
|
||||||
static void setup_sni_alpn_list(struct proto *p, config_setting_t* config_items, const char* name, int alpn)
|
#if 0
|
||||||
|
static void setup_sni_alpn_list(
|
||||||
|
struct config_protocols_item *p,
|
||||||
|
config_setting_t* config_items,
|
||||||
|
const char* name,
|
||||||
|
int alpn)
|
||||||
{
|
{
|
||||||
int num_probes, i, max_server_name_len, server_name_len;
|
int num_probes, i, max_server_name_len, server_name_len;
|
||||||
const char * config_item, *server_name;
|
const char * config_item, *server_name;
|
||||||
@ -307,7 +339,7 @@ static void setup_sni_alpn_list(struct proto *p, config_setting_t* config_items,
|
|||||||
p->data = (void*)tls_data_set_list(p->data, alpn, sni_hostname_list);
|
p->data = (void*)tls_data_set_list(p->data, alpn, sni_hostname_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_sni_alpn(struct proto *p, config_setting_t* prot)
|
static void setup_sni_alpn(struct config_protocols_item *p, config_setting_t* prot)
|
||||||
{
|
{
|
||||||
config_setting_t *sni_hostnames, *alpn_protocols;
|
config_setting_t *sni_hostnames, *alpn_protocols;
|
||||||
|
|
||||||
@ -323,11 +355,45 @@ static void setup_sni_alpn(struct proto *p, config_setting_t* prot)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
static void setup_sni_alpn(struct config_protocols_item *p, config_setting_t* prot)
|
||||||
|
{}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Extract configuration for protocols to connect to.
|
/* For each protocol in the configuration, resolve address and set up protocol
|
||||||
* out: newly-allocated list of protocols
|
* options if required
|
||||||
*/
|
*/
|
||||||
#ifdef LIBCONFIG
|
#ifdef LIBCONFIG
|
||||||
|
static int config_protocols()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < cfg.protocols_len; i++) {
|
||||||
|
struct config_protocols_item* p = &(cfg.protocols[i]);
|
||||||
|
if (resolve_split_name(&(p->saddr), p->host, p->port)) {
|
||||||
|
fprintf(stderr, "cannot resolve %s:%s\n", p->host, p->port);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->probe = get_probe(p->name);
|
||||||
|
if (!p->probe) {
|
||||||
|
fprintf(stderr, "%s: probe unknown\n", p->name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(cfg.protocols[i].name, "tls")) {
|
||||||
|
cfg.protocols[i].data = (void*)new_tls_data();
|
||||||
|
if (cfg.protocols[i].sni_hostnames_len)
|
||||||
|
tls_data_set_list(cfg.protocols[i].data, 0,
|
||||||
|
cfg.protocols[i].sni_hostnames,
|
||||||
|
cfg.protocols[i].sni_hostnames_len);
|
||||||
|
if (cfg.protocols[i].alpn_protocols_len)
|
||||||
|
tls_data_set_list(cfg.protocols[i].data, 1,
|
||||||
|
cfg.protocols[i].alpn_protocols,
|
||||||
|
cfg.protocols[i].alpn_protocols_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static int config_protocols(config_t *config, struct proto **prots)
|
static int config_protocols(config_t *config, struct proto **prots)
|
||||||
{
|
{
|
||||||
config_setting_t *setting, *prot, *patterns;
|
config_setting_t *setting, *prot, *patterns;
|
||||||
@ -398,6 +464,7 @@ static int config_protocols(config_t *config, struct proto **prots)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Parses a config file
|
/* Parses a config file
|
||||||
* in: *filename
|
* in: *filename
|
||||||
@ -406,11 +473,11 @@ static int config_protocols(config_t *config, struct proto **prots)
|
|||||||
* 1 on error, 0 on success
|
* 1 on error, 0 on success
|
||||||
*/
|
*/
|
||||||
#ifdef LIBCONFIG
|
#ifdef LIBCONFIG
|
||||||
static int config_parse(char *filename, struct addrinfo **listen, struct proto **prots)
|
static int config_parse(char *filename, struct addrinfo **listen, struct config_protocols_item **prots)
|
||||||
{
|
{
|
||||||
config_t config;
|
config_t config;
|
||||||
int timeout;
|
int res;
|
||||||
const char* str;
|
const char*err;
|
||||||
|
|
||||||
config_init(&config);
|
config_init(&config);
|
||||||
if (config_read_file(&config, filename) == CONFIG_FALSE) {
|
if (config_read_file(&config, filename) == CONFIG_FALSE) {
|
||||||
@ -429,32 +496,19 @@ static int config_parse(char *filename, struct addrinfo **listen, struct proto *
|
|||||||
config_error_text(&config));
|
config_error_text(&config));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
res = config_parser(config_lookup(&config, "/"), &cfg, &err);
|
||||||
if(config_lookup_bool(&config, "verbose", &verbose) == CONFIG_FALSE) {
|
if (!res) {
|
||||||
config_lookup_int(&config, "verbose", &verbose);
|
fprintf(stderr, "%s\n", err);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
config_lookup_bool(&config, "inetd", &inetd);
|
config_resolve_listen(listen);
|
||||||
config_lookup_bool(&config, "foreground", &foreground);
|
config_protocols();
|
||||||
config_lookup_bool(&config, "numeric", &numeric);
|
|
||||||
config_lookup_bool(&config, "transparent", &transparent);
|
|
||||||
|
|
||||||
if (config_lookup_int(&config, "timeout", (int *)&timeout) == CONFIG_TRUE) {
|
|
||||||
probing_timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_lookup_string(&config, "on-timeout", &str)) {
|
|
||||||
set_ontimeout(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
config_lookup_string(&config, "user", &user_name);
|
|
||||||
config_lookup_string(&config, "pidfile", &pid_file);
|
|
||||||
config_lookup_string(&config, "chroot", &chroot_path);
|
|
||||||
|
|
||||||
config_lookup_string(&config, "syslog_facility", &facility);
|
|
||||||
|
|
||||||
|
/*
|
||||||
config_listen(&config, listen);
|
config_listen(&config, listen);
|
||||||
config_protocols(&config, prots);
|
config_protocols(&config, prots);
|
||||||
|
*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -467,12 +521,12 @@ static int config_parse(char *filename, struct addrinfo **listen, struct proto *
|
|||||||
* prot: array of protocols
|
* prot: array of protocols
|
||||||
* n_prots: number of protocols in *prot
|
* n_prots: number of protocols in *prot
|
||||||
* */
|
* */
|
||||||
static void append_protocols(struct option *options, int n_opts, struct proto *prot , int n_prots)
|
static void append_protocols(struct option *options, int n_opts, struct config_protocols_item *prot , int n_prots)
|
||||||
{
|
{
|
||||||
int o, p;
|
int o, p;
|
||||||
|
|
||||||
for (o = n_opts, p = 0; p < n_prots; o++, p++) {
|
for (o = n_opts, p = 0; p < n_prots; o++, p++) {
|
||||||
options[o].name = prot[p].description;
|
options[o].name = prot[p].name;
|
||||||
options[o].has_arg = required_argument;
|
options[o].has_arg = required_argument;
|
||||||
options[o].flag = 0;
|
options[o].flag = 0;
|
||||||
options[o].val = p + PROT_SHIFT;
|
options[o].val = p + PROT_SHIFT;
|
||||||
@ -481,6 +535,7 @@ static void append_protocols(struct option *options, int n_opts, struct proto *p
|
|||||||
|
|
||||||
static void make_alloptions(void)
|
static void make_alloptions(void)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
builtins = get_builtins();
|
builtins = get_builtins();
|
||||||
|
|
||||||
/* Create all_options, composed of const_options followed by one option per
|
/* Create all_options, composed of const_options followed by one option per
|
||||||
@ -489,6 +544,7 @@ static void make_alloptions(void)
|
|||||||
CHECK_ALLOC(all_options, "calloc");
|
CHECK_ALLOC(all_options, "calloc");
|
||||||
memcpy(all_options, const_options, sizeof(const_options));
|
memcpy(all_options, const_options, sizeof(const_options));
|
||||||
append_protocols(all_options, ARRAY_SIZE(const_options) - 1, builtins, get_num_builtins());
|
append_protocols(all_options, ARRAY_SIZE(const_options) - 1, builtins, get_num_builtins());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Performs a first scan of command line options to see if a configuration file
|
/* Performs a first scan of command line options to see if a configuration file
|
||||||
@ -497,7 +553,7 @@ static void make_alloptions(void)
|
|||||||
*
|
*
|
||||||
* prots: newly-allocated list of configured protocols, if any.
|
* prots: newly-allocated list of configured protocols, if any.
|
||||||
*/
|
*/
|
||||||
static void cmdline_config(int argc, char* argv[], struct proto** prots)
|
static void cmdline_config(int argc, char* argv[], struct config_protocols_item** prots)
|
||||||
{
|
{
|
||||||
#ifdef LIBCONFIG
|
#ifdef LIBCONFIG
|
||||||
int c, res;
|
int c, res;
|
||||||
@ -513,7 +569,7 @@ static void cmdline_config(int argc, char* argv[], struct proto** prots)
|
|||||||
opterr = 0; /* we're missing protocol options at this stage so don't output errors */
|
opterr = 0; /* we're missing protocol options at this stage so don't output errors */
|
||||||
while ((c = getopt_long_only(argc, argv, optstr, all_options, NULL)) != -1) {
|
while ((c = getopt_long_only(argc, argv, optstr, all_options, NULL)) != -1) {
|
||||||
if (c == 'v') {
|
if (c == 'v') {
|
||||||
verbose++;
|
cfg.verbose++;
|
||||||
}
|
}
|
||||||
if (c == 'F') {
|
if (c == 'F') {
|
||||||
config_filename = optarg;
|
config_filename = optarg;
|
||||||
@ -522,10 +578,10 @@ static void cmdline_config(int argc, char* argv[], struct proto** prots)
|
|||||||
} else {
|
} else {
|
||||||
/* No configuration file specified -- try default file locations */
|
/* No configuration file specified -- try default file locations */
|
||||||
res = config_parse("/etc/sslh/sslh.cfg", &addr_listen, prots);
|
res = config_parse("/etc/sslh/sslh.cfg", &addr_listen, prots);
|
||||||
if (!res && verbose) fprintf(stderr, "Using /etc/sslh/sslh.cfg\n");
|
if (!res && cfg.verbose) fprintf(stderr, "Using /etc/sslh/sslh.cfg\n");
|
||||||
if (res) {
|
if (res) {
|
||||||
res = config_parse("/etc/sslh.cfg", &addr_listen, prots);
|
res = config_parse("/etc/sslh.cfg", &addr_listen, prots);
|
||||||
if (!res && verbose) fprintf(stderr, "Using /etc/sslh.cfg\n");
|
if (!res && cfg.verbose) fprintf(stderr, "Using /etc/sslh.cfg\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (res)
|
if (res)
|
||||||
@ -539,11 +595,13 @@ static void cmdline_config(int argc, char* argv[], struct proto** prots)
|
|||||||
|
|
||||||
/* Parse command-line options. prots points to a list of configured protocols,
|
/* Parse command-line options. prots points to a list of configured protocols,
|
||||||
* potentially non-allocated */
|
* potentially non-allocated */
|
||||||
static void parse_cmdline(int argc, char* argv[], struct proto* prots)
|
static void parse_cmdline(int argc, char* argv[], struct config_protocols_item* prots)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
int c;
|
int c;
|
||||||
struct addrinfo **a;
|
struct addrinfo **a;
|
||||||
struct proto *p;
|
struct config_protocols_item *p;
|
||||||
|
int background;
|
||||||
|
|
||||||
optind = 1;
|
optind = 1;
|
||||||
opterr = 1;
|
opterr = 1;
|
||||||
@ -556,7 +614,7 @@ next_arg:
|
|||||||
for (p = prots; p && p->next; p = p->next) {
|
for (p = prots; p && p->next; p = p->next) {
|
||||||
/* override if protocol was already defined by config file
|
/* override if protocol was already defined by config file
|
||||||
* (note it only overrides address and use builtin probe) */
|
* (note it only overrides address and use builtin probe) */
|
||||||
if (!strcmp(p->description, builtins[c-PROT_SHIFT].description)) {
|
if (!strcmp(p->name, builtins[c-PROT_SHIFT].name)) {
|
||||||
resolve_name(&(p->saddr), optarg);
|
resolve_name(&(p->saddr), optarg);
|
||||||
p->probe = builtins[c-PROT_SHIFT].probe;
|
p->probe = builtins[c-PROT_SHIFT].probe;
|
||||||
goto next_arg;
|
goto next_arg;
|
||||||
@ -583,10 +641,8 @@ next_arg:
|
|||||||
case 'F':
|
case 'F':
|
||||||
/* Legal option, but do nothing, it was already processed in
|
/* Legal option, but do nothing, it was already processed in
|
||||||
* cmdline_config() */
|
* cmdline_config() */
|
||||||
#ifndef LIBCONFIG
|
|
||||||
fprintf(stderr, "Built without libconfig support: configuration file not available.\n");
|
fprintf(stderr, "Built without libconfig support: configuration file not available.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
@ -631,16 +687,20 @@ next_arg:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
if (!prots) {
|
if (!prots) {
|
||||||
fprintf(stderr, "At least one target protocol must be specified.\n");
|
fprintf(stderr, "At least one target protocol must be specified.\n");
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
set_protocol_list(prots);
|
set_protocol_list(prots);
|
||||||
|
*/
|
||||||
|
|
||||||
/* If compiling with systemd socket support no need to require listen address */
|
/* If compiling with systemd socket support no need to require listen address */
|
||||||
#ifndef SYSTEMD
|
#ifndef SYSTEMD
|
||||||
if (!addr_listen && !inetd) {
|
if (!addr_listen && !cfg.inetd) {
|
||||||
fprintf(stderr, "No listening address specified; use at least one -p option\n");
|
fprintf(stderr, "No listening address specified; use at least one -p option\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -648,8 +708,9 @@ next_arg:
|
|||||||
|
|
||||||
/* Did command-line override foreground setting? */
|
/* Did command-line override foreground setting? */
|
||||||
if (background)
|
if (background)
|
||||||
foreground = 0;
|
cfg.foreground = 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -658,26 +719,26 @@ int main(int argc, char *argv[])
|
|||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind;
|
extern int optind;
|
||||||
int res, num_addr_listen;
|
int res, num_addr_listen;
|
||||||
struct proto* protocols = NULL;
|
struct config_protocols_item* protocols = NULL;
|
||||||
|
|
||||||
int *listen_sockets;
|
int *listen_sockets;
|
||||||
|
|
||||||
/* Init defaults */
|
/* Init defaults */
|
||||||
pid_file = NULL;
|
cfg.pidfile = NULL;
|
||||||
user_name = NULL;
|
cfg.user = NULL;
|
||||||
chroot_path = NULL;
|
cfg.chroot = NULL;
|
||||||
|
|
||||||
cmdline_config(argc, argv, &protocols);
|
cmdline_config(argc, argv, &protocols);
|
||||||
parse_cmdline(argc, argv, protocols);
|
parse_cmdline(argc, argv, protocols);
|
||||||
|
|
||||||
if (inetd)
|
if (cfg.inetd)
|
||||||
{
|
{
|
||||||
verbose = 0;
|
cfg.verbose = 0;
|
||||||
start_shoveler(0);
|
start_shoveler(0);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
printsettings();
|
printsettings();
|
||||||
|
|
||||||
num_addr_listen = start_listen_sockets(&listen_sockets, addr_listen);
|
num_addr_listen = start_listen_sockets(&listen_sockets, addr_listen);
|
||||||
@ -689,7 +750,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!foreground) {
|
if (!cfg.foreground) {
|
||||||
if (fork() > 0) exit(0); /* Detach */
|
if (fork() > 0) exit(0); /* Detach */
|
||||||
|
|
||||||
/* New session -- become group leader */
|
/* New session -- become group leader */
|
||||||
@ -701,16 +762,16 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
setup_signals();
|
setup_signals();
|
||||||
|
|
||||||
if (pid_file)
|
if (cfg.pidfile)
|
||||||
write_pid_file(pid_file);
|
write_pid_file(cfg.pidfile);
|
||||||
|
|
||||||
/* Open syslog connection before we drop privs/chroot */
|
/* Open syslog connection before we drop privs/chroot */
|
||||||
setup_syslog(argv[0]);
|
setup_syslog(argv[0]);
|
||||||
|
|
||||||
if (user_name || chroot_path)
|
if (cfg.user || cfg.chroot)
|
||||||
drop_privileges(user_name, chroot_path);
|
drop_privileges(cfg.user, cfg.chroot);
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
printcaps();
|
printcaps();
|
||||||
|
|
||||||
main_loop(listen_sockets, num_addr_listen);
|
main_loop(listen_sockets, num_addr_listen);
|
||||||
|
@ -60,7 +60,7 @@ int tidy_connection(struct connection *cnx, fd_set *fds, fd_set *fds2)
|
|||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
if (cnx->q[i].fd != -1) {
|
if (cnx->q[i].fd != -1) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "closing fd %d\n", cnx->q[i].fd);
|
fprintf(stderr, "closing fd %d\n", cnx->q[i].fd);
|
||||||
|
|
||||||
FD_CLR(cnx->q[i].fd, fds);
|
FD_CLR(cnx->q[i].fd, fds);
|
||||||
@ -111,7 +111,7 @@ int accept_new_connection(int listen_socket, struct connection *cnx[], int* cnx_
|
|||||||
/* nothing */
|
/* nothing */
|
||||||
}
|
}
|
||||||
if (free >= *cnx_size) {
|
if (free >= *cnx_size) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "buying more slots from the slot machine.\n");
|
fprintf(stderr, "buying more slots from the slot machine.\n");
|
||||||
new = realloc(*cnx, (*cnx_size + cnx_num_alloc) * sizeof((*cnx)[0]));
|
new = realloc(*cnx, (*cnx_size + cnx_num_alloc) * sizeof((*cnx)[0]));
|
||||||
if (!new) {
|
if (!new) {
|
||||||
@ -127,9 +127,9 @@ int accept_new_connection(int listen_socket, struct connection *cnx[], int* cnx_
|
|||||||
}
|
}
|
||||||
(*cnx)[free].q[0].fd = in_socket;
|
(*cnx)[free].q[0].fd = in_socket;
|
||||||
(*cnx)[free].state = ST_PROBING;
|
(*cnx)[free].state = ST_PROBING;
|
||||||
(*cnx)[free].probe_timeout = time(NULL) + probing_timeout;
|
(*cnx)[free].probe_timeout = time(NULL) + cfg.timeout;
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "accepted fd %d on slot %d\n", in_socket, free);
|
fprintf(stderr, "accepted fd %d on slot %d\n", in_socket, free);
|
||||||
|
|
||||||
return in_socket;
|
return in_socket;
|
||||||
@ -169,7 +169,7 @@ void shovel(struct connection *cnx, int active_fd,
|
|||||||
read_q = &cnx->q[active_fd];
|
read_q = &cnx->q[active_fd];
|
||||||
write_q = &cnx->q[1-active_fd];
|
write_q = &cnx->q[1-active_fd];
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "activity on fd%d\n", read_q->fd);
|
fprintf(stderr, "activity on fd%d\n", read_q->fd);
|
||||||
|
|
||||||
switch(fd2fd(write_q, read_q)) {
|
switch(fd2fd(write_q, read_q)) {
|
||||||
@ -223,7 +223,7 @@ void shovel_single(struct connection *cnx)
|
|||||||
if (FD_ISSET(cnx->q[i].fd, &fds_w)) {
|
if (FD_ISSET(cnx->q[i].fd, &fds_w)) {
|
||||||
res = flush_deferred(&cnx->q[i]);
|
res = flush_deferred(&cnx->q[i]);
|
||||||
if ((res == -1) && ((errno == EPIPE) || (errno == ECONNRESET))) {
|
if ((res == -1) && ((errno == EPIPE) || (errno == ECONNRESET))) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "%s socket closed\n", i ? "server" : "client");
|
fprintf(stderr, "%s socket closed\n", i ? "server" : "client");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -231,7 +231,7 @@ void shovel_single(struct connection *cnx)
|
|||||||
if (FD_ISSET(cnx->q[i].fd, &fds_r)) {
|
if (FD_ISSET(cnx->q[i].fd, &fds_r)) {
|
||||||
res = fd2fd(&cnx->q[1-i], &cnx->q[i]);
|
res = fd2fd(&cnx->q[1-i], &cnx->q[i]);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "socket closed\n");
|
fprintf(stderr, "socket closed\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -269,7 +269,7 @@ void connect_proxy(struct connection *cnx)
|
|||||||
close(in_socket);
|
close(in_socket);
|
||||||
close(out_socket);
|
close(out_socket);
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "connection closed down\n");
|
fprintf(stderr, "connection closed down\n");
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
@ -329,12 +329,12 @@ void main_loop(int listen_sockets[], int num_addr_listen)
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
memset(&tv, 0, sizeof(tv));
|
memset(&tv, 0, sizeof(tv));
|
||||||
tv.tv_sec = probing_timeout;
|
tv.tv_sec = cfg.timeout;
|
||||||
|
|
||||||
memcpy(&readfds, &fds_r, sizeof(readfds));
|
memcpy(&readfds, &fds_r, sizeof(readfds));
|
||||||
memcpy(&writefds, &fds_w, sizeof(writefds));
|
memcpy(&writefds, &fds_w, sizeof(writefds));
|
||||||
|
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "selecting... max_fd=%d num_probing=%d\n", max_fd, num_probing);
|
fprintf(stderr, "selecting... max_fd=%d num_probing=%d\n", max_fd, num_probing);
|
||||||
res = select(max_fd, &readfds, &writefds, NULL, num_probing ? &tv : NULL);
|
res = select(max_fd, &readfds, &writefds, NULL, num_probing ? &tv : NULL);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
@ -363,7 +363,7 @@ void main_loop(int listen_sockets[], int num_addr_listen)
|
|||||||
if ((res == -1) && ((errno == EPIPE) || (errno == ECONNRESET))) {
|
if ((res == -1) && ((errno == EPIPE) || (errno == ECONNRESET))) {
|
||||||
if (cnx[i].state == ST_PROBING) num_probing--;
|
if (cnx[i].state == ST_PROBING) num_probing--;
|
||||||
tidy_connection(&cnx[i], &fds_r, &fds_w);
|
tidy_connection(&cnx[i], &fds_r, &fds_w);
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "closed slot %d\n", i);
|
fprintf(stderr, "closed slot %d\n", i);
|
||||||
} else {
|
} else {
|
||||||
/* If no deferred data is left, stop monitoring the fd
|
/* If no deferred data is left, stop monitoring the fd
|
||||||
@ -383,7 +383,7 @@ void main_loop(int listen_sockets[], int num_addr_listen)
|
|||||||
for (j = 0; j < 2; j++) {
|
for (j = 0; j < 2; j++) {
|
||||||
if (is_fd_active(cnx[i].q[j].fd, &readfds) ||
|
if (is_fd_active(cnx[i].q[j].fd, &readfds) ||
|
||||||
((cnx[i].state == ST_PROBING) && (cnx[i].probe_timeout < time(NULL)))) {
|
((cnx[i].state == ST_PROBING) && (cnx[i].probe_timeout < time(NULL)))) {
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
fprintf(stderr, "processing fd%d slot %d\n", j, i);
|
fprintf(stderr, "processing fd%d slot %d\n", j, i);
|
||||||
|
|
||||||
switch (cnx[i].state) {
|
switch (cnx[i].state) {
|
||||||
@ -399,10 +399,10 @@ void main_loop(int listen_sockets[], int num_addr_listen)
|
|||||||
* data so probe the protocol */
|
* data so probe the protocol */
|
||||||
if ((cnx[i].probe_timeout < time(NULL))) {
|
if ((cnx[i].probe_timeout < time(NULL))) {
|
||||||
cnx[i].proto = timeout_protocol();
|
cnx[i].proto = timeout_protocol();
|
||||||
if (verbose)
|
if (cfg.verbose)
|
||||||
log_message(LOG_INFO,
|
log_message(LOG_INFO,
|
||||||
"timed out, connect to %s\n",
|
"timed out, connect to %s\n",
|
||||||
cnx[i].proto->description);
|
cnx[i].proto->name);
|
||||||
} else {
|
} else {
|
||||||
res = probe_client_protocol(&cnx[i]);
|
res = probe_client_protocol(&cnx[i]);
|
||||||
if (res == PROBE_AGAIN)
|
if (res == PROBE_AGAIN)
|
||||||
|
37
sslhconf.cfg
37
sslhconf.cfg
@ -1,8 +1,21 @@
|
|||||||
header: "sslh-conf.h";
|
header: "sslh-conf.h";
|
||||||
parser: "sslh-conf.c";
|
parser: "sslh-conf.c";
|
||||||
|
|
||||||
config: (
|
# List of includes to define runtime types
|
||||||
{ name: "verbose"; type: "boolean"; default: false },
|
# (bug in libconfig? if swallows the brackets if they start
|
||||||
|
# the string)
|
||||||
|
includes: (
|
||||||
|
"probe.h",
|
||||||
|
" <sys/types.h>",
|
||||||
|
" <sys/socket.h>",
|
||||||
|
" <netdb.h>"
|
||||||
|
);
|
||||||
|
|
||||||
|
config: {
|
||||||
|
name : "config",
|
||||||
|
type: "list",
|
||||||
|
items: (
|
||||||
|
{ name: "verbose"; type: "int"; default: 0; },
|
||||||
{ name: "foreground"; type: "boolean"; default: false; },
|
{ name: "foreground"; type: "boolean"; default: false; },
|
||||||
{ name: "inetd"; type: "boolean"; default: false; },
|
{ name: "inetd"; type: "boolean"; default: false; },
|
||||||
{ name: "numeric"; type: "boolean"; default: false; },
|
{ name: "numeric"; type: "boolean"; default: false; },
|
||||||
@ -10,7 +23,7 @@ config: (
|
|||||||
{ name: "timeout"; type: "int"; default: 2; },
|
{ name: "timeout"; type: "int"; default: 2; },
|
||||||
{ name: "user"; type: "string"; optional: true; },
|
{ name: "user"; type: "string"; optional: true; },
|
||||||
{ name: "pidfile"; type: "string"; optional: true; },
|
{ name: "pidfile"; type: "string"; optional: true; },
|
||||||
{ name: "chroot"; type: "string"; },
|
{ name: "chroot"; type: "string"; optional: true; },
|
||||||
{ name: "syslog_facility"; type: "string"; default: "auth"; },
|
{ name: "syslog_facility"; type: "string"; default: "auth"; },
|
||||||
|
|
||||||
{name: "on_timeout"; type: "string"; default: "ssh"; },
|
{name: "on_timeout"; type: "string"; default: "ssh"; },
|
||||||
@ -18,8 +31,8 @@ config: (
|
|||||||
{ name: "listen",
|
{ name: "listen",
|
||||||
type: "list",
|
type: "list",
|
||||||
items: (
|
items: (
|
||||||
{ name: "host"; type: "string"; },
|
{ name: "host"; type: "string"; var: true; },
|
||||||
{ name: "port"; type: "string"; },
|
{ name: "port"; type: "string"; var: true; },
|
||||||
{ name: "keepalive"; type: "boolean"; default: false; }
|
{ name: "keepalive"; type: "boolean"; default: false; }
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -28,8 +41,8 @@ config: (
|
|||||||
type: "list",
|
type: "list",
|
||||||
items: (
|
items: (
|
||||||
{ name: "name"; type: "string"; },
|
{ name: "name"; type: "string"; },
|
||||||
{ name: "host"; type: "string"; },
|
{ name: "host"; type: "string"; var: true; },
|
||||||
{ name: "port"; type: "string"; },
|
{ name: "port"; type: "string"; var: true; },
|
||||||
{ name: "service"; type: "string"; optional: true; },
|
{ name: "service"; type: "string"; optional: true; },
|
||||||
{ name: "fork"; type: "boolean"; default: false },
|
{ name: "fork"; type: "boolean"; default: false },
|
||||||
{ name: "log_level"; type: "int"; default: 1 },
|
{ name: "log_level"; type: "int"; default: 1 },
|
||||||
@ -45,8 +58,14 @@ config: (
|
|||||||
{ name: "regex_patterns",
|
{ name: "regex_patterns",
|
||||||
type: "array",
|
type: "array",
|
||||||
element_type: "string"
|
element_type: "string"
|
||||||
}
|
},
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
{ name: "probe"; type: "runtime"; c_type: "T_PROBE*" },
|
||||||
|
{ name: "saddr"; type: "runtime"; c_type: "struct addrinfo*" },
|
||||||
|
{ name: "data"; type: "runtime"; c_type: "void*" }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
6
test.cfg
6
test.cfg
@ -31,12 +31,12 @@ protocols:
|
|||||||
{ name: "xmpp"; host: "localhost"; port: "9009"; },
|
{ name: "xmpp"; host: "localhost"; port: "9009"; },
|
||||||
{ name: "adb"; host: "localhost"; port: "9010"; },
|
{ name: "adb"; host: "localhost"; port: "9010"; },
|
||||||
{ name: "tls"; host: "localhost"; port: "9021"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni1" ]; },
|
{ name: "tls"; host: "localhost"; port: "9021"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni1" ]; },
|
||||||
{ name: "ssl"; host: "localhost"; port: "9022"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni2", "sni3" ]; },
|
{ name: "tls"; host: "localhost"; port: "9022"; alpn_protocols: [ "alpn1", "alpn2" ]; sni_hostnames: [ "sni2", "sni3" ]; },
|
||||||
{ name: "tls"; host: "localhost"; port: "9023"; alpn_protocols: [ "alpn3" ]; },
|
{ name: "tls"; host: "localhost"; port: "9023"; alpn_protocols: [ "alpn3" ]; },
|
||||||
{ name: "tls"; host: "localhost"; port: "9024"; sni_hostnames: [ "sni3" ]; },
|
{ name: "tls"; host: "localhost"; port: "9024"; sni_hostnames: [ "sni3" ]; },
|
||||||
{ name: "ssl"; host: "localhost"; port: "9025"; },
|
{ name: "tls"; host: "localhost"; port: "9025"; },
|
||||||
{ name: "anyprot"; host: "localhost"; port: "9099"; }
|
{ name: "anyprot"; host: "localhost"; port: "9099"; }
|
||||||
);
|
);
|
||||||
|
|
||||||
on-timeout: "ssh";
|
on_timeout: "ssh";
|
||||||
|
|
||||||
|
39
tls.c
39
tls.c
@ -32,6 +32,7 @@
|
|||||||
#include <stdlib.h> /* malloc() */
|
#include <stdlib.h> /* malloc() */
|
||||||
#include <fnmatch.h> /* fnmatch() */
|
#include <fnmatch.h> /* fnmatch() */
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
#include "sslh-conf.h"
|
||||||
|
|
||||||
#define TLS_HEADER_LEN 5
|
#define TLS_HEADER_LEN 5
|
||||||
#define TLS_HANDSHAKE_CONTENT_TYPE 0x16
|
#define TLS_HANDSHAKE_CONTENT_TYPE 0x16
|
||||||
@ -48,14 +49,16 @@ typedef struct {
|
|||||||
|
|
||||||
struct TLSProtocol {
|
struct TLSProtocol {
|
||||||
TLS_MATCHMODE match_mode;
|
TLS_MATCHMODE match_mode;
|
||||||
char** sni_hostname_list;
|
int sni_list_len;
|
||||||
char** alpn_protocol_list;
|
const char** sni_hostname_list;
|
||||||
|
int alpn_list_len;
|
||||||
|
const char** alpn_protocol_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int parse_extensions(const struct TLSProtocol *, const char *, size_t);
|
static int parse_extensions(const struct TLSProtocol *, const char *, size_t);
|
||||||
static int parse_server_name_extension(const struct TLSProtocol *, const char *, size_t);
|
static int parse_server_name_extension(const struct TLSProtocol *, const char *, size_t);
|
||||||
static int parse_alpn_extension(const struct TLSProtocol *, const char *, size_t);
|
static int parse_alpn_extension(const struct TLSProtocol *, const char *, size_t);
|
||||||
static int has_match(char**, const char*, size_t);
|
static int has_match(const char**, size_t, const char*, size_t);
|
||||||
|
|
||||||
/* Parse a TLS packet for the Server Name Indication and ALPN extension in the client
|
/* Parse a TLS packet for the Server Name Indication and ALPN extension in the client
|
||||||
* hello handshake, returning a status code
|
* hello handshake, returning a status code
|
||||||
@ -79,14 +82,14 @@ parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t da
|
|||||||
|
|
||||||
tls_content_type = data[0];
|
tls_content_type = data[0];
|
||||||
if (tls_content_type != TLS_HANDSHAKE_CONTENT_TYPE) {
|
if (tls_content_type != TLS_HANDSHAKE_CONTENT_TYPE) {
|
||||||
if (verbose) fprintf(stderr, "Request did not begin with TLS handshake.\n");
|
if (cfg.verbose) fprintf(stderr, "Request did not begin with TLS handshake.\n");
|
||||||
return TLS_EPROTOCOL;
|
return TLS_EPROTOCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls_version_major = data[1];
|
tls_version_major = data[1];
|
||||||
tls_version_minor = data[2];
|
tls_version_minor = data[2];
|
||||||
if (tls_version_major < 3) {
|
if (tls_version_major < 3) {
|
||||||
if (verbose) fprintf(stderr, "Received SSL %d.%d handshake which cannot be parsed.\n",
|
if (cfg.verbose) fprintf(stderr, "Received SSL %d.%d handshake which cannot be parsed.\n",
|
||||||
tls_version_major, tls_version_minor);
|
tls_version_major, tls_version_minor);
|
||||||
|
|
||||||
return TLS_EVERSION;
|
return TLS_EVERSION;
|
||||||
@ -108,7 +111,7 @@ parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t da
|
|||||||
return TLS_EPROTOCOL;
|
return TLS_EPROTOCOL;
|
||||||
}
|
}
|
||||||
if (data[pos] != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
|
if (data[pos] != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
|
||||||
if (verbose) fprintf(stderr, "Not a client hello\n");
|
if (cfg.verbose) fprintf(stderr, "Not a client hello\n");
|
||||||
|
|
||||||
return TLS_EPROTOCOL;
|
return TLS_EPROTOCOL;
|
||||||
}
|
}
|
||||||
@ -141,7 +144,7 @@ parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t da
|
|||||||
pos += 1 + len;
|
pos += 1 + len;
|
||||||
|
|
||||||
if (pos == data_len && tls_version_major == 3 && tls_version_minor == 0) {
|
if (pos == data_len && tls_version_major == 3 && tls_version_minor == 0) {
|
||||||
if (verbose) fprintf(stderr, "Received SSL 3.0 handshake without extensions\n");
|
if (cfg.verbose) fprintf(stderr, "Received SSL 3.0 handshake without extensions\n");
|
||||||
return TLS_EVERSION;
|
return TLS_EVERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,13 +222,13 @@ parse_server_name_extension(const struct TLSProtocol *tls_data, const char *data
|
|||||||
|
|
||||||
switch (data[pos]) { /* name type */
|
switch (data[pos]) { /* name type */
|
||||||
case 0x00: /* host_name */
|
case 0x00: /* host_name */
|
||||||
if(has_match(tls_data->sni_hostname_list, data + pos + 3, len)) {
|
if(has_match(tls_data->sni_hostname_list, tls_data->sni_list_len, data + pos + 3, len)) {
|
||||||
return len;
|
return len;
|
||||||
} else {
|
} else {
|
||||||
return TLS_ENOEXT;
|
return TLS_ENOEXT;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if (verbose) fprintf(stderr, "Unknown server name extension name type: %d\n",
|
if (cfg.verbose) fprintf(stderr, "Unknown server name extension name type: %d\n",
|
||||||
data[pos]);
|
data[pos]);
|
||||||
}
|
}
|
||||||
pos += 3 + len;
|
pos += 3 + len;
|
||||||
@ -248,10 +251,10 @@ parse_alpn_extension(const struct TLSProtocol *tls_data, const char *data, size_
|
|||||||
if (pos + 1 + len > data_len)
|
if (pos + 1 + len > data_len)
|
||||||
return TLS_EPROTOCOL;
|
return TLS_EPROTOCOL;
|
||||||
|
|
||||||
if (len > 0 && has_match(tls_data->alpn_protocol_list, data + pos + 1, len)) {
|
if (len > 0 && has_match(tls_data->alpn_protocol_list, tls_data->alpn_list_len, data + pos + 1, len)) {
|
||||||
return len;
|
return len;
|
||||||
} else if (len > 0) {
|
} else if (len > 0) {
|
||||||
if (verbose) fprintf(stderr, "Unknown ALPN name: %.*s\n", (int)len, data + pos + 1);
|
if (cfg.verbose) fprintf(stderr, "Unknown ALPN name: %.*s\n", (int)len, data + pos + 1);
|
||||||
}
|
}
|
||||||
pos += 1 + len;
|
pos += 1 + len;
|
||||||
}
|
}
|
||||||
@ -263,15 +266,17 @@ parse_alpn_extension(const struct TLSProtocol *tls_data, const char *data, size_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
has_match(char** list, const char* name, size_t name_len) {
|
has_match(const char** list, size_t list_len, const char* name, size_t name_len) {
|
||||||
char **item;
|
const char **item;
|
||||||
|
int i;
|
||||||
char *name_nullterminated = malloc(name_len+1);
|
char *name_nullterminated = malloc(name_len+1);
|
||||||
CHECK_ALLOC(name_nullterminated, "malloc");
|
CHECK_ALLOC(name_nullterminated, "malloc");
|
||||||
memcpy(name_nullterminated, name, name_len);
|
memcpy(name_nullterminated, name, name_len);
|
||||||
name_nullterminated[name_len]='\0';
|
name_nullterminated[name_len]='\0';
|
||||||
|
|
||||||
for (item = list; *item; item++) {
|
for (i = 0; i < list_len; i++) {
|
||||||
if (verbose) fprintf(stderr, "matching [%.*s] with [%s]\n", (int)name_len, name, *item);
|
item = &list[i];
|
||||||
|
if (cfg.verbose) fprintf(stderr, "matching [%.*s] with [%s]\n", (int)name_len, name, *item);
|
||||||
if(!fnmatch(*item, name_nullterminated, 0)) {
|
if(!fnmatch(*item, name_nullterminated, 0)) {
|
||||||
free(name_nullterminated);
|
free(name_nullterminated);
|
||||||
return 1;
|
return 1;
|
||||||
@ -292,12 +297,14 @@ new_tls_data() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct TLSProtocol *
|
struct TLSProtocol *
|
||||||
tls_data_set_list(struct TLSProtocol *tls_data, int alpn, char** list) {
|
tls_data_set_list(struct TLSProtocol *tls_data, int alpn, const char** list, size_t list_len) {
|
||||||
if (alpn) {
|
if (alpn) {
|
||||||
tls_data->alpn_protocol_list = list;
|
tls_data->alpn_protocol_list = list;
|
||||||
|
tls_data->alpn_list_len = list_len;
|
||||||
tls_data->match_mode.tls_match_alpn = 1;
|
tls_data->match_mode.tls_match_alpn = 1;
|
||||||
} else {
|
} else {
|
||||||
tls_data->sni_hostname_list = list;
|
tls_data->sni_hostname_list = list;
|
||||||
|
tls_data->sni_list_len = list_len;
|
||||||
tls_data->match_mode.tls_match_sni = 1;
|
tls_data->match_mode.tls_match_sni = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
tls.h
2
tls.h
@ -33,7 +33,7 @@ struct TLSProtocol;
|
|||||||
int parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t data_len);
|
int parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t data_len);
|
||||||
|
|
||||||
struct TLSProtocol *new_tls_data();
|
struct TLSProtocol *new_tls_data();
|
||||||
struct TLSProtocol *tls_data_set_list(struct TLSProtocol *, int, char**);
|
struct TLSProtocol *tls_data_set_list(struct TLSProtocol *, int, const char**, size_t);
|
||||||
|
|
||||||
#define TLS_MATCH 1
|
#define TLS_MATCH 1
|
||||||
#define TLS_NOMATCH 0
|
#define TLS_NOMATCH 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user