From aa17061e26a06624d7bb375baeffe4a905842a02 Mon Sep 17 00:00:00 2001 From: Toni Uhlig Date: Thu, 11 Aug 2022 17:05:57 +0200 Subject: [PATCH 1/4] add openvpn udp probe Signed-off-by: Toni Uhlig --- probe.c | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/probe.c b/probe.c index aa9db03..4f704a0 100644 --- a/probe.c +++ b/probe.c @@ -137,15 +137,50 @@ static int is_ssh_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_ * http://www.fengnet.com/book/vpns%20illustrated%20tunnels%20%20vpnsand%20ipsec/ch08lev1sec5.html * and OpenVPN ssl.c, ssl.h and options.c */ +#define OVPN_OPCODE_MASK 0xF8 +#define OVPN_CONTROL_HARD_RESET_CLIENT_V1 (0x01 << 3) +#define OVPN_CONTROL_HARD_RESET_CLIENT_V2 (0x07 << 3) +#define OVPN_HMAC_128 16 +#define OVPN_HMAC_160 20 +#define OVPN_HARD_RESET_PACKET_ID_OFFSET(hmac_size) (9 + hmac_size) static int is_openvpn_protocol (const char*p,ssize_t len, struct sslhcfg_protocols_item* proto) { int packet_len; - if (len < 2) - return PROBE_AGAIN; + if (proto->is_udp == 0) + { + if (len < 2) + return PROBE_AGAIN; - packet_len = ntohs(*(uint16_t*)p); - return packet_len == len - 2; + packet_len = ntohs(*(uint16_t*)p); + return packet_len == len - 2; + } else { + if (len < 1) + return PROBE_NEXT; + + if ((p[0] & OVPN_OPCODE_MASK) != OVPN_CONTROL_HARD_RESET_CLIENT_V1 && + (p[0] & OVPN_OPCODE_MASK) != OVPN_CONTROL_HARD_RESET_CLIENT_V2) + return PROBE_NEXT; + + /* The detection pattern above may not be reliable enough. + * Check the packet id: OpenVPN sents five initial packets + * whereas the packet id is increased with every transmitted datagram. + */ + + if (len <= OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_128)) + return PROBE_NEXT; + + if (ntohl(*(uint32_t*)(p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_128))) <= 5u) + return PROBE_MATCH; + + if (len <= OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160)) + return PROBE_NEXT; + + if (ntohl(*(uint32_t*)(p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160))) <= 5u) + return PROBE_MATCH; + + return PROBE_NEXT; + } } /* Is the buffer the beginning of a tinc connections? From a6c5e07d696052be215225277c36a28b966b91b8 Mon Sep 17 00:00:00 2001 From: Toni Uhlig Date: Sat, 13 Aug 2022 22:18:26 +0200 Subject: [PATCH 2/4] add some config sanity checks, fixes #307 Signed-off-by: Toni Uhlig --- sslh-main.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/sslh-main.c b/sslh-main.c index eeb2f34..0009498 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -167,7 +167,10 @@ static void config_protocols() } -void config_sanity_check(struct sslhcfg_item* cfg) { +void config_sanity_check(struct sslhcfg_item* cfg) +{ + size_t i; + /* If compiling with systemd socket support no need to require listen address */ #ifndef SYSTEMD if (!cfg->listen_len && !cfg->inetd) { @@ -175,6 +178,32 @@ void config_sanity_check(struct sslhcfg_item* cfg) { exit(1); } #endif + + for (i = 0; i < cfg->protocols_len; ++i) { + if (strcmp(cfg->protocols[i].name, "tls")) { + if (cfg->protocols[i].sni_hostnames_len) { + print_message(msg_config_error, "name: \"%s\"; host: \"%s\"; port: \"%s\": " + "Config option sni_hostnames is only applicable for tls\n", + cfg->protocols[i].name, cfg->protocols[i].host, cfg->protocols[i].port); + exit(1); + } + if (cfg->protocols[i].alpn_protocols_len) { + print_message(msg_config_error, "name: \"%s\"; host: \"%s\"; port: \"%s\": " + "Config option alpn_protocols is only applicable for tls\n", + cfg->protocols[i].name, cfg->protocols[i].host, cfg->protocols[i].port); + exit(1); + } + } + + if (cfg->protocols[i].is_udp) { + if (cfg->protocols[i].tfo_ok) { + print_message(msg_config_error, "name: \"%s\"; host: \"%s\"; port: \"%s\": " + "Config option tfo_ok is not applicable for udp connections\n", + cfg->protocols[i].name, cfg->protocols[i].host, cfg->protocols[i].port); + exit(1); + } + } + } } From 8d124e1085f6da32034f249cb5ec4d59841cdf4b Mon Sep 17 00:00:00 2001 From: Toni Uhlig Date: Sat, 13 Aug 2022 23:40:46 +0200 Subject: [PATCH 3/4] changed select(nfds, ...) to select(nfds + 1, ...), see `man 3 select` Signed-off-by: Toni Uhlig --- sslh-select.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sslh-select.c b/sslh-select.c index 82620d4..aa8b14e 100644 --- a/sslh-select.c +++ b/sslh-select.c @@ -143,9 +143,9 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) memcpy(&readfds, &fd_info.watchers->fds_r, sizeof(readfds)); memcpy(&writefds, &fd_info.watchers->fds_w, sizeof(writefds)); - print_message(msg_fd, "selecting... max_fd=%d num_probing=%d\n", + print_message(msg_fd, "selecting... max_fd=%d num_probing=%d\n", fd_info.watchers->max_fd, fd_info.num_probing); - res = select(fd_info.watchers->max_fd, &readfds, &writefds, + res = select(fd_info.watchers->max_fd + 1, &readfds, &writefds, NULL, fd_info.num_probing ? &tv : NULL); if (res < 0) perror("select"); From 4cf3749e73f4525f53c789a14d09bf3c5a29c926 Mon Sep 17 00:00:00 2001 From: Toni Uhlig Date: Sun, 14 Aug 2022 10:42:58 +0200 Subject: [PATCH 4/4] add teamspeak3 (voice only) probe Signed-off-by: Toni Uhlig --- example.cfg | 2 +- probe.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/example.cfg b/example.cfg index cd1a8ee..b818e89 100644 --- a/example.cfg +++ b/example.cfg @@ -123,7 +123,7 @@ protocols: udp_timeout: 20; # Time after which the "connection" is forgotten regex_patterns: [ "hello" ]; }, # Forward Teamspeak3 (Voice only) - { name: "regex"; host: "localhost"; is_udp: true; port: "9987"; regex_patterns: [ "TS3INIT1" ]; }, + { name: "teamspeak"; host: "localhost"; is_udp: true; port: "9987"; }, # Forward IETF QUIC-50 ("Q050" -> "\x51\x30\x35\x30") # Remember that the regex needs to be adjusted for every supported QUIC version. { name: "regex"; host: "localhost"; is_udp: true; port: "4433"; regex_patterns: [ "\x51\x30\x35\x30" ]; }, diff --git a/probe.c b/probe.c index aa9db03..ecc2e73 100644 --- a/probe.c +++ b/probe.c @@ -40,6 +40,7 @@ static int is_tls_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_ static int is_adb_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item*); static int is_socks5_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item*); static int is_syslog_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item*); +static int is_teamspeak_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item*); static int is_true(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto) { return 1; } /* Table of protocols that have a built-in probe @@ -55,6 +56,7 @@ static struct protocol_probe_desc builtins[] = { { "adb", is_adb_protocol }, { "socks5", is_socks5_protocol }, { "syslog", is_syslog_protocol }, + { "teamspeak", is_teamspeak_protocol }, { "anyprot", is_true } }; @@ -318,6 +320,14 @@ static int is_syslog_protocol(const char *p, ssize_t len, struct sslhcfg_protoco return 0; } +static int is_teamspeak_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto) +{ + if (len < 8) + return PROBE_NEXT; + + return !strncmp(p, "TS3INIT1", len); +} + static int regex_probe(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto) { #ifdef ENABLE_REGEX