forked from yrutschle/sslh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tcp-probe.c
98 lines (85 loc) · 2.99 KB
/
tcp-probe.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
# tcp-probe.c: TCP code that is common to the sslh-fork and sslh-[ev|select]
#
# Copyright (C) 2022 Yves Rutschle
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more
# details.
#
# The full text for the General Public License is here:
# http://www.gnu.org/licenses/gpl.html
*/
#include "probe.h"
static struct sslhcfg_protocols_item** tcp_protocols;
static int tcp_protocols_len = 0;
/*
* Read the beginning of data coming from the client connection and check if
* it's a known protocol.
* Return PROBE_AGAIN if not enough data, or PROBE_MATCH if it succeeded in
* which case cnx->proto is set to the appropriate protocol.
*/
int probe_client_protocol(struct connection *cnx)
{
char buffer[BUFSIZ];
ssize_t n;
n = read(cnx->q[0].fd, buffer, sizeof(buffer));
/* It's possible that read() returns an error, e.g. if the client
* disconnected between the previous call to select() and now. If that
* happens, we just connect to the default protocol so the caller of this
* function does not have to deal with a specific failure condition (the
* connection will just fail later normally). */
if (n > 0) {
defer_write(&cnx->q[1], buffer, n);
return probe_buffer(cnx->q[1].begin_deferred_data,
cnx->q[1].deferred_data_size,
tcp_protocols, tcp_protocols_len,
&cnx->proto
);
}
/* read() returned an error, so just connect to the last protocol to die */
cnx->proto = &cfg.protocols[cfg.protocols_len-1];
return PROBE_MATCH;
}
static void tcp_protocol_list_init(void)
{
for (int i = 0; i < cfg.protocols_len; i++) {
struct sslhcfg_protocols_item* p = &cfg.protocols[i];
if (!p->is_udp) {
tcp_protocols_len++;
tcp_protocols = realloc(tcp_protocols, tcp_protocols_len * sizeof(*tcp_protocols));
tcp_protocols[tcp_protocols_len-1] = p;
}
}
}
/* Configuration sanity check for TCP:
* - If there is a listening socket, there must be at least one target
*/
static void tcp_sanity_check(void)
{
int tcp_present = 0;
for (int i = 0; i < cfg.listen_len; i++) {
struct sslhcfg_listen_item* p = &cfg.listen[i];
if (!p->is_udp) {
tcp_present = 1;
break;
}
}
if (tcp_present && !tcp_protocols_len) {
print_message(msg_config_error, "At least one TCP target protocol must be specified.\n");
exit(2);
}
}
void tcp_init(void)
{
tcp_protocol_list_init();
tcp_sanity_check();
}