git ssb

0+

cel / sslh



Tree: 8af039d3eb3e890482fd6755532d7786a104cae8

Files: 8af039d3eb3e890482fd6755532d7786a104cae8 / probe.c

11459 bytesRaw
1/*
2# probe.c: Code for probing protocols
3#
4# Copyright (C) 2007-2015 Yves Rutschle
5#
6# This program is free software; you can redistribute it
7# and/or modify it under the terms of the GNU General Public
8# License as published by the Free Software Foundation; either
9# version 2 of the License, or (at your option) any later
10# version.
11#
12# This program is distributed in the hope that it will be
13# useful, but WITHOUT ANY WARRANTY; without even the implied
14# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more
16# details.
17#
18# The full text for the General Public License is here:
19# http://www.gnu.org/licenses/gpl.html
20*/
21
22#define _GNU_SOURCE
23#include <stdio.h>
24#ifdef LIBPCRE
25#include <regex.h>
26#endif
27#include <ctype.h>
28#include "probe.h"
29
30
31
32static int is_ssh_protocol(const char *p, int len, struct proto*);
33static int is_openvpn_protocol(const char *p, int len, struct proto*);
34static int is_tinc_protocol(const char *p, int len, struct proto*);
35static int is_xmpp_protocol(const char *p, int len, struct proto*);
36static int is_http_protocol(const char *p, int len, struct proto*);
37static int is_tls_protocol(const char *p, int len, struct proto*);
38static int is_adb_protocol(const char *p, int len, struct proto*);
39static int is_true(const char *p, int len, struct proto* proto) { return 1; }
40
41/* Table of protocols that have a built-in probe
42 */
43static struct proto builtins[] = {
44 /* description service saddr log_level probe */
45 { "ssh", "sshd", NULL, 1, is_ssh_protocol},
46 { "openvpn", NULL, NULL, 1, is_openvpn_protocol },
47 { "tinc", NULL, NULL, 1, is_tinc_protocol },
48 { "xmpp", NULL, NULL, 1, is_xmpp_protocol },
49 { "http", NULL, NULL, 1, is_http_protocol },
50 { "ssl", NULL, NULL, 1, is_tls_protocol },
51 { "tls", NULL, NULL, 1, is_tls_protocol },
52 { "adb", NULL, NULL, 1, is_adb_protocol },
53 { "anyprot", NULL, NULL, 1, is_true }
54};
55
56static struct proto *protocols;
57static char* on_timeout = "ssh";
58
59struct proto* get_builtins(void) {
60 return builtins;
61}
62
63int get_num_builtins(void) {
64 return ARRAY_SIZE(builtins);
65}
66
67/* Sets the protocol name to connect to in case of timeout */
68void set_ontimeout(const char* name)
69{
70 int res = asprintf(&on_timeout, "%s", name);
71 CHECK_RES_DIE(res, "asprintf");
72}
73
74/* Returns the protocol to connect to in case of timeout;
75 * if not found, return the first protocol specified
76 */
77struct proto* timeout_protocol(void)
78{
79 struct proto* p = get_first_protocol();
80 for (; p && strcmp(p->description, on_timeout); p = p->next);
81 if (p) return p;
82 return get_first_protocol();
83}
84
85/* returns the first protocol (caller can then follow the *next pointers) */
86struct proto* get_first_protocol(void)
87{
88 return protocols;
89}
90
91void set_protocol_list(struct proto* prots)
92{
93 protocols = prots;
94}
95
96/* From http://grapsus.net/blog/post/Hexadecimal-dump-in-C */
97#define HEXDUMP_COLS 16
98void hexdump(const char *mem, unsigned int len)
99{
100 unsigned int i, j;
101
102 for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
103 {
104 /* print offset */
105 if(i % HEXDUMP_COLS == 0)
106 printf("0x%06x: ", i);
107
108 /* print hex data */
109 if(i < len)
110 printf("%02x ", 0xFF & mem[i]);
111 else /* end of block, just aligning for ASCII dump */
112 printf(" ");
113
114 /* print ASCII dump */
115 if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) {
116 for(j = i - (HEXDUMP_COLS - 1); j <= i; j++) {
117 if(j >= len) /* end of block, not really printing */
118 putchar(' ');
119 else if(isprint(mem[j])) /* printable char */
120 putchar(0xFF & mem[j]);
121 else /* other char */
122 putchar('.');
123 }
124 putchar('\n');
125 }
126 }
127}
128
129/* Is the buffer the beginning of an SSH connection? */
130static int is_ssh_protocol(const char *p, int len, struct proto *proto)
131{
132 if (len < 4)
133 return PROBE_AGAIN;
134
135 return !strncmp(p, "SSH-", 4);
136}
137
138/* Is the buffer the beginning of an OpenVPN connection?
139 *
140 * Code inspired from OpenVPN port-share option; however, OpenVPN code is
141 * wrong: users using pre-shared secrets have non-initialised key_id fields so
142 * p[3] & 7 should not be looked at, and also the key_method can be specified
143 * to 1 which changes the opcode to P_CONTROL_HARD_RESET_CLIENT_V1.
144 * See:
145 * http://www.fengnet.com/book/vpns%20illustrated%20tunnels%20%20vpnsand%20ipsec/ch08lev1sec5.html
146 * and OpenVPN ssl.c, ssl.h and options.c
147 */
148static int is_openvpn_protocol (const char*p,int len, struct proto *proto)
149{
150 int packet_len;
151
152 if (len < 2)
153 return PROBE_AGAIN;
154
155 packet_len = ntohs(*(uint16_t*)p);
156 return packet_len == len - 2;
157}
158
159/* Is the buffer the beginning of a tinc connections?
160 * Protocol is documented here: http://www.tinc-vpn.org/documentation/tinc.pdf
161 * First connection starts with "0 " in 1.0.15)
162 * */
163static int is_tinc_protocol( const char *p, int len, struct proto *proto)
164{
165 if (len < 2)
166 return PROBE_AGAIN;
167
168 return !strncmp(p, "0 ", 2);
169}
170
171/* Is the buffer the beginning of a jabber (XMPP) connections?
172 * (Protocol is documented (http://tools.ietf.org/html/rfc6120) but for lazy
173 * clients, just checking first frame containing "jabber" in xml entity)
174 * */
175static int is_xmpp_protocol( const char *p, int len, struct proto *proto)
176{
177 /* sometimes the word 'jabber' shows up late in the initial string,
178 sometimes after a newline. this makes sure we snarf the entire preamble
179 and detect it. (fixed for adium/pidgin) */
180 if (len < 50)
181 return PROBE_AGAIN;
182
183 return memmem(p, len, "jabber", 6) ? 1 : 0;
184}
185
186static int probe_http_method(const char *p, int len, const char *opt)
187{
188 if (len < strlen(opt))
189 return PROBE_AGAIN;
190
191 return !strncmp(p, opt, len);
192}
193
194/* Is the buffer the beginning of an HTTP connection? */
195static int is_http_protocol(const char *p, int len, struct proto *proto)
196{
197 int res;
198 /* If it's got HTTP in the request (HTTP/1.1) then it's HTTP */
199 if (memmem(p, len, "HTTP", 4))
200 return PROBE_MATCH;
201
202#define PROBE_HTTP_METHOD(opt) if ((res = probe_http_method(p, len, opt)) != PROBE_NEXT) return res
203
204 /* Otherwise it could be HTTP/1.0 without version: check if it's got an
205 * HTTP method (RFC2616 5.1.1) */
206 PROBE_HTTP_METHOD("OPTIONS");
207 PROBE_HTTP_METHOD("GET");
208 PROBE_HTTP_METHOD("HEAD");
209 PROBE_HTTP_METHOD("POST");
210 PROBE_HTTP_METHOD("PUT");
211 PROBE_HTTP_METHOD("DELETE");
212 PROBE_HTTP_METHOD("TRACE");
213 PROBE_HTTP_METHOD("CONNECT");
214
215#undef PROBE_HTTP_METHOD
216
217 return PROBE_NEXT;
218}
219
220static int is_sni_alpn_protocol(const char *p, int len, struct proto *proto)
221{
222 int valid_tls;
223
224 valid_tls = parse_tls_header(proto->data, p, len);
225
226 if(valid_tls < 0)
227 return -1 == valid_tls ? PROBE_AGAIN : PROBE_NEXT;
228
229 /* There *was* a valid match */
230 return PROBE_MATCH;
231}
232
233static int is_tls_protocol(const char *p, int len, struct proto *proto)
234{
235 if (len < 3)
236 return PROBE_AGAIN;
237
238 /* TLS packet starts with a record "Hello" (0x16), followed by version
239 * (0x03 0x00-0x03) (RFC6101 A.1)
240 * This means we reject SSLv2 and lower, which is actually a good thing (RFC6176)
241 */
242 return p[0] == 0x16 && p[1] == 0x03 && ( p[2] >= 0 && p[2] <= 0x03);
243}
244
245static int is_adb_protocol(const char *p, int len, struct proto *proto)
246{
247 if (len < 30)
248 return PROBE_AGAIN;
249
250 /* The initial ADB host->device packet has a command type of CNXN, and a
251 * data payload starting with "host:". Note that current versions of the
252 * client hardcode "host::" (with empty serialno and banner fields) but
253 * other clients may populate those fields.
254 *
255 * We aren't checking amessage.data_length, under the assumption that
256 * a packet >= 30 bytes long will have "something" in the payload field.
257 */
258 return !memcmp(&p[0], "CNXN", 4) && !memcmp(&p[24], "host:", 5);
259}
260
261static int regex_probe(const char *p, int len, struct proto *proto)
262{
263#ifdef LIBPCRE
264 regex_t **probe = proto->data;
265 regmatch_t pos = { 0, len };
266
267 for (; *probe && regexec(*probe, p, 0, &pos, REG_STARTEND); probe++)
268 /* try them all */;
269
270 return (*probe != NULL);
271#else
272 /* Should never happen as we check when loading config file */
273 fprintf(stderr, "FATAL: regex probe called but not built in\n");
274 exit(5);
275#endif
276}
277
278/*
279 * Read the beginning of data coming from the client connection and check if
280 * it's a known protocol.
281 * Return PROBE_AGAIN if not enough data, or PROBE_MATCH if it succeeded in
282 * which case cnx->proto is set to the appropriate protocol.
283 */
284int probe_client_protocol(struct connection *cnx)
285{
286 char buffer[BUFSIZ];
287 struct proto *p;
288 int n;
289
290 n = read(cnx->q[0].fd, buffer, sizeof(buffer));
291 /* It's possible that read() returns an error, e.g. if the client
292 * disconnected between the previous call to select() and now. If that
293 * happens, we just connect to the default protocol so the caller of this
294 * function does not have to deal with a specific failure condition (the
295 * connection will just fail later normally). */
296 if (n > 0) {
297 int res = PROBE_NEXT;
298
299 defer_write(&cnx->q[1], buffer, n);
300
301 for (p = cnx->proto; p && res == PROBE_NEXT; p = p->next) {
302 if (! p->probe) continue;
303 if (verbose) fprintf(stderr, "probing for %s\n", p->description);
304
305 cnx->proto = p;
306 res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p);
307 }
308 if (res != PROBE_NEXT)
309 return res;
310 }
311
312 if (verbose)
313 fprintf(stderr,
314 "all probes failed, connecting to first protocol: %s\n",
315 protocols->description);
316
317 /* If none worked, return the first one affected (that's completely
318 * arbitrary) */
319 cnx->proto = protocols;
320 return PROBE_MATCH;
321}
322
323/* Returns the structure for specified protocol or NULL if not found */
324static struct proto* get_protocol(const char* description)
325{
326 int i;
327
328 for (i = 0; i < ARRAY_SIZE(builtins); i++) {
329 if (!strcmp(builtins[i].description, description)) {
330 return &builtins[i];
331 }
332 }
333 return NULL;
334}
335
336/* Returns the probe for specified protocol:
337 * parameter is the description in builtins[], or "regex"
338 * */
339T_PROBE* get_probe(const char* description) {
340 struct proto* p = get_protocol(description);
341
342 if (p)
343 return p->probe;
344
345 /* Special case of "regex" probe (we don't want to set it in builtins
346 * because builtins is also used to build the command-line options and
347 * regexp is not legal on the command line)*/
348 if (!strcmp(description, "regex"))
349 return regex_probe;
350
351 /* Special case of "sni/alpn" probe for same reason as above*/
352 if (!strcmp(description, "sni_alpn"))
353 return is_sni_alpn_protocol;
354
355 /* Special case of "timeout" is allowed as a probe name in the
356 * configuration file even though it's not really a probe */
357 if (!strcmp(description, "timeout"))
358 return is_true;
359
360 return NULL;
361}
362
363
364

Built with git-ssb-web