git ssb

0+

cel / sslh



Tree: 960373f54f4b7127b4be72a3bad8bd74327fee96

Files: 960373f54f4b7127b4be72a3bad8bd74327fee96 / probe.c

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

Built with git-ssb-web