make UDP hash size configurable

This commit is contained in:
yrutschle 2022-04-10 09:03:53 +02:00
parent 21d00bd29d
commit 35036c94c7
10 changed files with 186 additions and 34 deletions

View File

@ -9,6 +9,11 @@ vNEXT:
message class can be set to go to stderr, syslog, or message class can be set to go to stderr, syslog, or
both. Classes are documented in example.cfg. both. Classes are documented in example.cfg.
UDP connections are now managed in a hash to avoid
linear searches. The downside is that the number of
UDP connections is a hard limit, configurable with
the 'udp_max_connections', which defaults to 1024.
inetd merges stderr output to what is sent to the inetd merges stderr output to what is sent to the
client, which is a security issue as it might give client, which is a security issue as it might give
information to an attacker. When inetd is activated, information to an attacker. When inetd is activated,

12
echo_test.cfg Normal file
View File

@ -0,0 +1,12 @@
# TODO: c2s does not warn if udp: 1 (instead of 'true')
udp: true;
prefix: "hello";
listen: "localhost:9000";
listen-host: "localhost";
listen-port: "9000";

View File

@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Fri Apr 1 19:34:31 2022. * on Sun Apr 10 08:52:32 2022.
# conf2struct: generate libconf parsers that read to structs # conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2021 Yves Rutschle # Copyright (C) 2018-2021 Yves Rutschle

View File

@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Fri Apr 1 19:34:31 2022. * on Sun Apr 10 08:52:32 2022.
# conf2struct: generate libconf parsers that read to structs # conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2021 Yves Rutschle # Copyright (C) 2018-2021 Yves Rutschle

109
echoѕrv-conf.h Normal file
View File

@ -0,0 +1,109 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Sat Nov 7 09:19:26 2020.
# conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2019 Yves Rutschle
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef C2S_SSLHCFG_H
#define C2S_SSLHCFG_H
#ifdef LIBCONFIG
# include <libconfig.h>
#endif
#include "probe.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
struct sslhcfg_listen_item {
char* host;
char* port;
int keepalive;
};
struct sslhcfg_protocols_item {
char* name;
char* host;
char* port;
int service_is_present;
char* service;
int fork;
int tfo_ok;
int log_level;
int keepalive;
size_t sni_hostnames_len;
char** sni_hostnames;
size_t alpn_protocols_len;
char** alpn_protocols;
size_t regex_patterns_len;
char** regex_patterns;
int minlength_is_present;
int minlength;
T_PROBE* probe;
struct addrinfo* saddr;
void* data;
};
struct sslhcfg_item {
char* prefix;
int verbose;
int foreground;
int inetd;
int numeric;
int transparent;
int timeout;
int user_is_present;
char* user;
int pidfile_is_present;
char* pidfile;
int chroot_is_present;
char* chroot;
char* syslog_facility;
char* on_timeout;
size_t listen_len;
struct sslhcfg_listen_item* listen;
size_t protocols_len;
struct sslhcfg_protocols_item* protocols;
};
int sslhcfg_parse_file(
const char* filename,
struct sslhcfg_item* sslhcfg,
const char** errmsg);
void sslhcfg_fprint(
FILE* out,
struct sslhcfg_item *sslhcfg,
int depth);
int sslhcfg_cl_parse(
int argc,
char* argv[],
struct sslhcfg_item *sslhcfg);
#endif

View File

@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Fri Apr 1 19:34:30 2022. * on Sun Apr 10 08:52:30 2022.
# conf2struct: generate libconf parsers that read to structs # conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2021 Yves Rutschle # Copyright (C) 2018-2021 Yves Rutschle
@ -460,6 +460,7 @@ struct arg_file* sslhcfg_conffile;
struct arg_lit* sslhcfg_numeric; struct arg_lit* sslhcfg_numeric;
struct arg_lit* sslhcfg_transparent; struct arg_lit* sslhcfg_transparent;
struct arg_int* sslhcfg_timeout; struct arg_int* sslhcfg_timeout;
struct arg_int* sslhcfg_udp_max_connections;
struct arg_str* sslhcfg_user; struct arg_str* sslhcfg_user;
struct arg_str* sslhcfg_pidfile; struct arg_str* sslhcfg_pidfile;
struct arg_str* sslhcfg_chroot; struct arg_str* sslhcfg_chroot;
@ -809,7 +810,7 @@ static struct config_desc table_sslhcfg_listen[] = {
}, },
{ 0 } { 0 }
}; };
static struct config_desc table_sslhcfg[] = { static struct config_desc table_sslhcfg[] = {
@ -1085,6 +1086,22 @@ static struct config_desc table_sslhcfg[] = {
/* default_val*/ .default_val.def_int = 5 /* default_val*/ .default_val.def_int = 5
}, },
{
/* name */ "udp_max_connections",
/* type */ CFG_INT,
/* sub_group*/ NULL,
/* arg_cl */ & sslhcfg_udp_max_connections,
/* base_addr */ NULL,
/* offset */ offsetof(struct sslhcfg_item, udp_max_connections),
/* offset_len */ 0,
/* offset_present */ 0,
/* size */ sizeof(int),
/* array_type */ -1,
/* mandatory */ 0,
/* optional */ 0,
/* default_val*/ .default_val.def_int = 1024
},
{ {
/* name */ "user", /* name */ "user",
/* type */ CFG_STRING, /* type */ CFG_STRING,
@ -1309,7 +1326,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: listen */ { /* arg: listen */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_listen, .arg_cl = & sslhcfg_listen,
.base_entry = & table_sslhcfg [23], .base_entry = & table_sslhcfg [24],
.targets = sslhcfg_listen_targets, .targets = sslhcfg_listen_targets,
@ -1321,7 +1338,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: ssh */ { /* arg: ssh */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_ssh, .arg_cl = & sslhcfg_ssh,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_ssh_targets, .targets = sslhcfg_ssh_targets,
@ -1333,7 +1350,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: tls */ { /* arg: tls */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_tls, .arg_cl = & sslhcfg_tls,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_tls_targets, .targets = sslhcfg_tls_targets,
@ -1345,7 +1362,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: openvpn */ { /* arg: openvpn */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_openvpn, .arg_cl = & sslhcfg_openvpn,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_openvpn_targets, .targets = sslhcfg_openvpn_targets,
@ -1357,7 +1374,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: tinc */ { /* arg: tinc */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_tinc, .arg_cl = & sslhcfg_tinc,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_tinc_targets, .targets = sslhcfg_tinc_targets,
@ -1369,7 +1386,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: xmpp */ { /* arg: xmpp */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_xmpp, .arg_cl = & sslhcfg_xmpp,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_xmpp_targets, .targets = sslhcfg_xmpp_targets,
@ -1381,7 +1398,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: http */ { /* arg: http */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_http, .arg_cl = & sslhcfg_http,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_http_targets, .targets = sslhcfg_http_targets,
@ -1393,7 +1410,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: adb */ { /* arg: adb */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_adb, .arg_cl = & sslhcfg_adb,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_adb_targets, .targets = sslhcfg_adb_targets,
@ -1405,7 +1422,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: socks5 */ { /* arg: socks5 */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_socks5, .arg_cl = & sslhcfg_socks5,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_socks5_targets, .targets = sslhcfg_socks5_targets,
@ -1417,7 +1434,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: syslog */ { /* arg: syslog */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_syslog, .arg_cl = & sslhcfg_syslog,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_syslog_targets, .targets = sslhcfg_syslog_targets,
@ -1429,7 +1446,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: anyprot */ { /* arg: anyprot */
.regex = "(.+):(\\w+)", .regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_anyprot, .arg_cl = & sslhcfg_anyprot,
.base_entry = & table_sslhcfg [24], .base_entry = & table_sslhcfg [25],
.targets = sslhcfg_anyprot_targets, .targets = sslhcfg_anyprot_targets,
@ -2111,6 +2128,7 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg)
sslhcfg_numeric = arg_litn("n", "numeric", 0, 1, "Print IP addresses and ports as numbers"), sslhcfg_numeric = arg_litn("n", "numeric", 0, 1, "Print IP addresses and ports as numbers"),
sslhcfg_transparent = arg_litn(NULL, "transparent", 0, 1, "Set up as a transparent proxy"), sslhcfg_transparent = arg_litn(NULL, "transparent", 0, 1, "Set up as a transparent proxy"),
sslhcfg_timeout = arg_intn("t", "timeout", "<n>", 0, 1, "Set up timeout before connecting to default target"), sslhcfg_timeout = arg_intn("t", "timeout", "<n>", 0, 1, "Set up timeout before connecting to default target"),
sslhcfg_udp_max_connections = arg_intn(NULL, "udp-max-connections", "<n>", 0, 1, "Number of concurrent UDP connections"),
sslhcfg_user = arg_strn("u", "user", "<str>", 0, 1, "Username to change to after set-up"), sslhcfg_user = arg_strn("u", "user", "<str>", 0, 1, "Username to change to after set-up"),
sslhcfg_pidfile = arg_strn("P", "pidfile", "<file>", 0, 1, "Path to file to store PID of current instance"), sslhcfg_pidfile = arg_strn("P", "pidfile", "<file>", 0, 1, "Path to file to store PID of current instance"),
sslhcfg_chroot = arg_strn("C", "chroot", "<path>", 0, 1, "Root to change to after set-up"), sslhcfg_chroot = arg_strn("C", "chroot", "<path>", 0, 1, "Root to change to after set-up"),
@ -2327,6 +2345,9 @@ void sslhcfg_fprint(
fprintf(out, "timeout: %d", sslhcfg->timeout); fprintf(out, "timeout: %d", sslhcfg->timeout);
fprintf(out, "\n"); fprintf(out, "\n");
indent(out, depth); indent(out, depth);
fprintf(out, "udp_max_connections: %d", sslhcfg->udp_max_connections);
fprintf(out, "\n");
indent(out, depth);
fprintf(out, "user: %s", sslhcfg->user); fprintf(out, "user: %s", sslhcfg->user);
if (! sslhcfg->user_is_present) if (! sslhcfg->user_is_present)
fprintf(out, " <unset>"); fprintf(out, " <unset>");

View File

@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Fri Apr 1 19:34:30 2022. * on Sun Apr 10 08:52:30 2022.
# conf2struct: generate libconf parsers that read to structs # conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2021 Yves Rutschle # Copyright (C) 2018-2021 Yves Rutschle
@ -92,6 +92,7 @@ struct sslhcfg_item {
int numeric; int numeric;
int transparent; int transparent;
int timeout; int timeout;
int udp_max_connections;
int user_is_present; int user_is_present;
char* user; char* user;
int pidfile_is_present; int pidfile_is_present;

View File

@ -67,20 +67,25 @@ static void printsettings(void)
for (i = 0; i < cfg.protocols_len; i++ ) { for (i = 0; i < cfg.protocols_len; i++ ) {
p = &cfg.protocols[i]; p = &cfg.protocols[i];
print_message(msg_config, print_message(msg_config,
"%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s] [%s] [%s]\n", "%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s] [%s] [%s]\n",
p->name, p->name,
sprintaddr(buf, sizeof(buf), p->saddr), sprintaddr(buf, sizeof(buf), p->saddr),
p->service, p->service,
p->log_level, p->log_level,
p->saddr->ai_family, p->saddr->ai_family,
p->saddr->ai_addr->sa_family, p->saddr->ai_addr->sa_family,
p->keepalive ? "keepalive" : "", p->keepalive ? "keepalive" : "",
p->fork ? "fork" : "", p->fork ? "fork" : "",
p->transparent ? "transparent" : "" p->transparent ? "transparent" : ""
); );
} }
print_message(msg_config, "timeout: %d\non-timeout: %s\n", cfg.timeout, print_message(msg_config,
timeout_protocol()->name); "timeout: %d\n"
"on-timeout: %s\n"
"UDP hash size: %d\n",
cfg.timeout,
timeout_protocol()->name,
cfg.udp_max_connections);
} }

View File

@ -67,6 +67,8 @@ config: {
{ name: "timeout"; type: "int"; default: 5; { name: "timeout"; type: "int"; default: 5;
short: "t"; short: "t";
description: "Set up timeout before connecting to default target"; }, description: "Set up timeout before connecting to default target"; },
{ name: "udp_max_connections"; type: "int"; default: 1024;
description: "Number of concurrent UDP connections"; },
{ name: "user"; type: "string"; optional: true; { name: "user"; type: "string"; optional: true;
short: "u"; short: "u";
description: "Username to change to after set-up"; }, description: "Username to change to after set-up"; },

View File

@ -27,9 +27,6 @@
#include "sslh-conf.h" #include "sslh-conf.h"
#include "udp-listener.h" #include "udp-listener.h"
/* How many concurrent connections we manage */
#define HASH_SIZE 1024
/* returns date at which this socket times out. */ /* returns date at which this socket times out. */
static int udp_timeout(struct connection* cnx) static int udp_timeout(struct connection* cnx)
{ {
@ -93,7 +90,7 @@ static int hash_make_key(hash_item new)
* */ * */
void udp_init(struct loop_info* fd_info) void udp_init(struct loop_info* fd_info)
{ {
fd_info->hash_sources = hash_init(HASH_SIZE, &hash_make_key, &cnx_cmp); fd_info->hash_sources = hash_init(cfg.udp_max_connections, &hash_make_key, &cnx_cmp);
} }
@ -228,7 +225,7 @@ int udp_c2s_forward(int sockfd, struct loop_info* fd_info)
res = new_source(fd_info->hash_sources, cnx); res = new_source(fd_info->hash_sources, cnx);
if (res == -1) { if (res == -1) {
print_message(msg_connections_error, "Out of hash space for new incoming UDP connection"); print_message(msg_connections_error, "Out of hash space for new incoming UDP connection -- increaѕe udp_max_connections");
collection_remove_cnx(collection, cnx); collection_remove_cnx(collection, cnx);
return -1; return -1;
} }