mirror of
https://github.com/yrutschle/sslh.git
synced 2025-04-14 08:07:14 +03:00
Merge branch 'tfo'
This commit is contained in:
commit
67eb471c6f
@ -1,4 +1,9 @@
|
||||
vNEXT:
|
||||
vNEXT:
|
||||
Added TCP_FASTOPEN support for client sockets (if
|
||||
tfo_ok is specified in their configuration) and for
|
||||
listenint socket, if all client protocols support it.
|
||||
(Craig Andrews)
|
||||
|
||||
Added 'minlength' option to skip a probe if less
|
||||
than that many bytes have been received (mostly for
|
||||
regex)
|
||||
|
39
common.c
39
common.c
@ -86,6 +86,24 @@ int get_fd_sockets(int *sockfd[])
|
||||
return sd;
|
||||
}
|
||||
|
||||
/* Set TCP_FASTOPEN on listening socket if all client protocols support it */
|
||||
int make_listen_tfo(int s)
|
||||
{
|
||||
int i, qlen = 5;
|
||||
|
||||
/* Don't do it if not supported */
|
||||
if (!TCP_FASTOPEN)
|
||||
return;
|
||||
|
||||
/* Don't do it if any protocol does not specify it */
|
||||
for (i = 0; i < cfg.protocols_len; i++) {
|
||||
if (! cfg.protocols[i].tfo_ok)
|
||||
return;
|
||||
}
|
||||
|
||||
return setsockopt(s, SOL_SOCKET, TCP_FASTOPEN, (char*)&qlen, sizeof(qlen));
|
||||
}
|
||||
|
||||
/* Starts listening sockets on specified addresses.
|
||||
* IN: addr[], num_addr
|
||||
* OUT: *sockfd[] pointer to newly-allocated array of file descriptors
|
||||
@ -134,6 +152,9 @@ int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list)
|
||||
res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one));
|
||||
check_res_dump(CR_DIE, res, addr, "setsockopt(SO_REUSEADDR)");
|
||||
|
||||
res = make_listen_tfo((*sockfd)[i]);
|
||||
check_res_dump(CR_WARN, res, addr, "setsockopt(TCP_FASTOPEN)");
|
||||
|
||||
if (addr->ai_flags & SO_KEEPALIVE) {
|
||||
res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(one));
|
||||
check_res_dump(CR_DIE, res, addr, "setsockopt(SO_KEEPALIVE)");
|
||||
@ -277,18 +298,28 @@ int connect_addr(struct connection *cnx, int fd_from)
|
||||
log_message(LOG_ERR, "forward to %s failed:socket: %s\n",
|
||||
cnx->proto->name, strerror(errno));
|
||||
} else {
|
||||
one = 1;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, &one, sizeof(one));
|
||||
/* no need to check return value; if it's not supported, that's okay */
|
||||
|
||||
if (cfg.transparent) {
|
||||
res = bind_peer(fd, fd_from);
|
||||
CHECK_RES_RETURN(res, "bind_peer");
|
||||
}
|
||||
res = connect(fd, a->ai_addr, a->ai_addrlen);
|
||||
if (res == -1) {
|
||||
log_message(LOG_ERR, "forward to %s failed:connect: %s\n",
|
||||
cnx->proto->name, strerror(errno));
|
||||
close(fd);
|
||||
switch (errno) {
|
||||
case EINPROGRESS:
|
||||
/* Can't be done yet, or TFO already done */
|
||||
break;
|
||||
|
||||
default:
|
||||
log_message(LOG_ERR, "forward to %s failed:connect: %s\n",
|
||||
cnx->proto->name, strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
} else {
|
||||
if (cnx->proto->keepalive) {
|
||||
one = 1;
|
||||
res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(one));
|
||||
CHECK_RES_RETURN(res, "setsockopt(SO_KEEPALIVE)");
|
||||
}
|
||||
|
8
common.h
8
common.h
@ -67,6 +67,14 @@
|
||||
#define IP_FREEBIND 0
|
||||
#endif
|
||||
|
||||
#ifndef TCP_FASTOPEN
|
||||
#define TCP_FASTOPEN 0
|
||||
#endif
|
||||
|
||||
#ifndef TCP_FASTOPEN_CONNECT
|
||||
#define TCP_FASTOPEN_CONNECT 30 /* Attempt FastOpen with connect. */
|
||||
#endif
|
||||
|
||||
enum connection_state {
|
||||
ST_PROBING=1, /* Waiting for timeout to find where to forward */
|
||||
ST_SHOVELING /* Connexion is established */
|
||||
|
19
example.cfg
19
example.cfg
@ -41,6 +41,7 @@ listen:
|
||||
# connection (default is off)
|
||||
# fork: Should a new process be forked for this protocol?
|
||||
# (only useful for sslh-select)
|
||||
# tfo_ok: Set to true if the server supports TCP FAST OPEN
|
||||
#
|
||||
# Probe-specific options:
|
||||
# (sslh will try each probe in order they are declared, and
|
||||
@ -66,28 +67,26 @@ listen:
|
||||
|
||||
protocols:
|
||||
(
|
||||
{ name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; keepalive: true; fork: true;
|
||||
listen: ( { host: "hello"; port: "xmpp" }, { host: "world";
|
||||
port: "dns" } ),
|
||||
},
|
||||
{ name: "ssh"; service: "ssh"; host: "localhost"; port: "22";
|
||||
keepalive: true; fork: true; tfo_ok: true },
|
||||
{ name: "http"; host: "localhost"; port: "80"; },
|
||||
|
||||
# match BOTH ALPN/SNI
|
||||
{ name: "tls"; host: "localhost"; port: "5223"; alpn_protocols: [ "xmpp-client" ]; sni_hostnames: [ "im.somethingelse.net" ]; log_level: 0;},
|
||||
{ name: "tls"; host: "localhost"; port: "5223"; alpn_protocols: [ "xmpp-client" ]; sni_hostnames: [ "im.somethingelse.net" ]; log_level: 0; tfo_ok: true },
|
||||
|
||||
# just match ALPN
|
||||
{ name: "tls"; host: "localhost"; port: "443"; alpn_protocols: [ "h2", "http/1.1", "spdy/1", "spdy/2", "spdy/3" ]; log_level: 0; },
|
||||
{ name: "tls"; host: "localhost"; port: "xmpp-client"; alpn_protocols: [ "xmpp-client" ]; log_level: 0;},
|
||||
{ name: "tls"; host: "localhost"; port: "443"; alpn_protocols: [ "h2", "http/1.1", "spdy/1", "spdy/2", "spdy/3" ]; log_level: 0; tfo_ok: true },
|
||||
{ name: "tls"; host: "localhost"; port: "xmpp-client"; alpn_protocols: [ "xmpp-client" ]; log_level: 0; tfo_ok: true },
|
||||
|
||||
# just match SNI
|
||||
{ name: "tls"; host: "localhost"; port: "993"; sni_hostnames: [ "mail.rutschle.net", "mail.englishintoulouse.com" ]; log_level: 0; },
|
||||
{ name: "tls"; host: "localhost"; port: "xmpp-client"; sni_hostnames: [ "im.rutschle.net", "im.englishintoulouse.com" ]; log_level: 0;},
|
||||
{ name: "tls"; host: "localhost"; port: "993"; sni_hostnames: [ "mail.rutschle.net", "mail.englishintoulouse.com" ]; log_level: 0; tfo_ok: true },
|
||||
{ name: "tls"; host: "localhost"; port: "xmpp-client"; sni_hostnames: [ "im.rutschle.net", "im.englishintoulouse.com" ]; log_level: 0; tfo_ok: true },
|
||||
|
||||
# Let's Encrypt (tls-sni-* challenges)
|
||||
{ name: "tls"; host: "localhost"; port: "letsencrypt-client"; sni_hostnames: [ "*.*.acme.invalid" ]; log_level: 0;},
|
||||
|
||||
# catch anything else TLS
|
||||
{ name: "tls"; host: "localhost"; port: "443"; },
|
||||
{ name: "tls"; host: "localhost"; port: "443"; tfo_ok: true },
|
||||
|
||||
# Regex examples -- better use the built-in probes for real-world use!
|
||||
# OpenVPN
|
||||
|
15
sslh-conf.c
15
sslh-conf.c
@ -1,5 +1,5 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sat Mar 9 12:35:49 2019. */
|
||||
* on Sun Mar 10 09:52:17 2019. */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
@ -10,6 +10,7 @@
|
||||
static void sslhcfg_protocols_init(struct sslhcfg_protocols_item* cfg) {
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
cfg->fork = 0;
|
||||
cfg->tfo_ok = 0;
|
||||
cfg->log_level = 1;
|
||||
cfg->keepalive = 0;
|
||||
}
|
||||
@ -94,6 +95,12 @@ static int sslhcfg_protocols_parser(
|
||||
return 0;
|
||||
} ;
|
||||
}
|
||||
if (config_setting_lookup(cfg, "tfo_ok")) {
|
||||
if (config_setting_lookup_bool(cfg, "tfo_ok", &sslhcfg_protocols->tfo_ok) == CONFIG_FALSE) {
|
||||
*errmsg = "Parsing of option \"tfo_ok\" failed";
|
||||
return 0;
|
||||
} ;
|
||||
}
|
||||
if (config_setting_lookup(cfg, "log_level")) {
|
||||
if (config_setting_lookup_int(cfg, "log_level", &sslhcfg_protocols->log_level) == CONFIG_FALSE) {
|
||||
*errmsg = "Parsing of option \"log_level\" failed";
|
||||
@ -358,6 +365,8 @@ static void sslhcfg_protocols_fprint(
|
||||
indent(out, depth);
|
||||
fprintf(out, "fork: %d\n", sslhcfg_protocols->fork);
|
||||
indent(out, depth);
|
||||
fprintf(out, "tfo_ok: %d\n", sslhcfg_protocols->tfo_ok);
|
||||
indent(out, depth);
|
||||
fprintf(out, "log_level: %d\n", sslhcfg_protocols->log_level);
|
||||
indent(out, depth);
|
||||
fprintf(out, "keepalive: %d\n", sslhcfg_protocols->keepalive);
|
||||
@ -646,6 +655,7 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg) {
|
||||
group->port = calloc(1, param_len + 1);
|
||||
memcpy(group->port, sslhcfg_ssh->sval [cl_i]+pmatch[2].rm_so, param_len);
|
||||
group->fork = *((char*)"1") - '0';
|
||||
group->tfo_ok = *((char*)"1") - '0';
|
||||
}
|
||||
#define MAX_MATCH 10
|
||||
for (cl_i = 0; cl_i < sslhcfg_tls->count; cl_i++) {
|
||||
@ -695,6 +705,7 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg) {
|
||||
param_len = pmatch[2].rm_eo - pmatch[2].rm_so;
|
||||
group->port = calloc(1, param_len + 1);
|
||||
memcpy(group->port, sslhcfg_tls->sval [cl_i]+pmatch[2].rm_so, param_len);
|
||||
group->tfo_ok = *((char*)"1") - '0';
|
||||
}
|
||||
#define MAX_MATCH 10
|
||||
for (cl_i = 0; cl_i < sslhcfg_openvpn->count; cl_i++) {
|
||||
@ -744,6 +755,7 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg) {
|
||||
param_len = pmatch[2].rm_eo - pmatch[2].rm_so;
|
||||
group->port = calloc(1, param_len + 1);
|
||||
memcpy(group->port, sslhcfg_openvpn->sval [cl_i]+pmatch[2].rm_so, param_len);
|
||||
group->tfo_ok = *((char*)"1") - '0';
|
||||
}
|
||||
#define MAX_MATCH 10
|
||||
for (cl_i = 0; cl_i < sslhcfg_tinc->count; cl_i++) {
|
||||
@ -793,6 +805,7 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg) {
|
||||
param_len = pmatch[2].rm_eo - pmatch[2].rm_so;
|
||||
group->port = calloc(1, param_len + 1);
|
||||
memcpy(group->port, sslhcfg_tinc->sval [cl_i]+pmatch[2].rm_so, param_len);
|
||||
group->tfo_ok = *((char*)"1") - '0';
|
||||
}
|
||||
#define MAX_MATCH 10
|
||||
for (cl_i = 0; cl_i < sslhcfg_xmpp->count; cl_i++) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sat Mar 9 12:35:49 2019. */
|
||||
* on Sun Mar 10 09:52:17 2019. */
|
||||
|
||||
#ifndef C2S_SSLHCFG_H
|
||||
#define C2S_SSLHCFG_H
|
||||
@ -23,6 +23,7 @@ struct sslhcfg_protocols_item {
|
||||
int service_is_present;
|
||||
const char* service;
|
||||
int fork;
|
||||
int tfo_ok;
|
||||
int log_level;
|
||||
int keepalive;
|
||||
size_t sni_hostnames_len;
|
||||
|
14
sslhconf.cfg
14
sslhconf.cfg
@ -66,6 +66,8 @@ config: {
|
||||
{ name: "port"; type: "string"; var: true; },
|
||||
{ name: "service"; type: "string"; optional: true; },
|
||||
{ name: "fork"; type: "boolean"; default: false },
|
||||
{ name: "tfo_ok"; type: "boolean"; default: false;
|
||||
description: "Set to true if this protocol supports TCP FAST OPEN" },
|
||||
{ name: "log_level"; type: "int"; default: 1 },
|
||||
{ name: "keepalive"; type: "boolean"; default: false },
|
||||
{ name: "sni_hostnames",
|
||||
@ -118,7 +120,8 @@ cl_groups: (
|
||||
{ path: "name"; value: "ssh" },
|
||||
{ path: "host"; value: "$1" },
|
||||
{ path: "port"; value: "$2" },
|
||||
{ path: "fork"; value: 1 }
|
||||
{ path: "fork"; value: 1 },
|
||||
{ path: "tfo_ok"; value: 1 }
|
||||
);
|
||||
},
|
||||
{ name: "tls"; pattern: "(\w+):(\w+)"; description: "Set up TLS/SSL target";
|
||||
@ -128,7 +131,8 @@ cl_groups: (
|
||||
targets: (
|
||||
{ path: "name"; value: "tls" },
|
||||
{ path: "host"; value: "$1" },
|
||||
{ path: "port"; value: "$2" }
|
||||
{ path: "port"; value: "$2" },
|
||||
{ path: "tfo_ok"; value: 1 }
|
||||
);
|
||||
},
|
||||
{ name: "openvpn"; pattern: "(\w+):(\w+)"; description: "Set up OpenVPN target";
|
||||
@ -138,7 +142,8 @@ cl_groups: (
|
||||
targets: (
|
||||
{ path: "name"; value: "openvpn" },
|
||||
{ path: "host"; value: "$1" },
|
||||
{ path: "port"; value: "$2" }
|
||||
{ path: "port"; value: "$2" },
|
||||
{ path: "tfo_ok"; value: 1 }
|
||||
);
|
||||
},
|
||||
{ name: "tinc"; pattern: "(\w+):(\w+)"; description: "Set up tinc target";
|
||||
@ -148,7 +153,8 @@ cl_groups: (
|
||||
targets: (
|
||||
{ path: "name"; value: "openvpn" },
|
||||
{ path: "host"; value: "$1" },
|
||||
{ path: "port"; value: "$2" }
|
||||
{ path: "port"; value: "$2" },
|
||||
{ path: "tfo_ok"; value: 1 }
|
||||
);
|
||||
},
|
||||
{ name: "xmpp"; pattern: "(\w+):(\w+)"; description: "Set up XMPP target";
|
||||
|
Loading…
x
Reference in New Issue
Block a user