git ssb

0+

cel / sslh



Tree: 389ab9fbfff529ad82a4e44b91e6169872775dd3

Files: 389ab9fbfff529ad82a4e44b91e6169872775dd3 / probe.c

11760 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 probe */
45 { "ssh", "sshd", NULL, is_ssh_protocol},
46 { "openvpn", NULL, NULL, is_openvpn_protocol },
47 { "tinc", NULL, NULL, is_tinc_protocol },
48 { "xmpp", NULL, NULL, is_xmpp_protocol },
49 { "http", NULL, NULL, is_http_protocol },
50 { "ssl", NULL, NULL, is_tls_protocol },
51 { "tls", NULL, NULL, is_tls_protocol },
52 { "adb", NULL, NULL, is_adb_protocol },
53 { "anyprot", NULL, NULL, 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_protocol(const char *p, int len, struct proto *proto)
221{
222 int valid_tls;
223 char *hostname;
224 char **sni_hostname;
225
226 valid_tls = parse_tls_header(p, len, &hostname);
227
228 if(valid_tls < 0)
229 return -1 == valid_tls ? PROBE_AGAIN : PROBE_NEXT;
230
231 if (verbose) fprintf(stderr, "sni hostname: %s\n", hostname);
232
233 /* Assume does not match */
234 valid_tls = PROBE_NEXT;
235
236 for (sni_hostname = proto->data; *sni_hostname; sni_hostname++) {
237 fprintf(stderr, "matching [%s] with [%s]\n", hostname, *sni_hostname);
238 if(!strcmp(hostname, *sni_hostname)) {
239 valid_tls = PROBE_MATCH;
240 break;
241 }
242 }
243
244 free(hostname);
245 return valid_tls;
246}
247
248static int is_tls_protocol(const char *p, int len, struct proto *proto)
249{
250 if (len < 3)
251 return PROBE_AGAIN;
252
253 /* TLS packet starts with a record "Hello" (0x16), followed by version
254 * (0x03 0x00-0x03) (RFC6101 A.1)
255 * This means we reject SSLv2 and lower, which is actually a good thing (RFC6176)
256 */
257 return p[0] == 0x16 && p[1] == 0x03 && ( p[2] >= 0 && p[2] <= 0x03);
258}
259
260static int is_adb_protocol(const char *p, int len, struct proto *proto)
261{
262 if (len < 30)
263 return PROBE_AGAIN;
264
265 /* The initial ADB host->device packet has a command type of CNXN, and a
266 * data payload starting with "host:". Note that current versions of the
267 * client hardcode "host::" (with empty serialno and banner fields) but
268 * other clients may populate those fields.
269 *
270 * We aren't checking amessage.data_length, under the assumption that
271 * a packet >= 30 bytes long will have "something" in the payload field.
272 */
273 return !memcmp(&p[0], "CNXN", 4) && !memcmp(&p[24], "host:", 5);
274}
275
276static int regex_probe(const char *p, int len, struct proto *proto)
277{
278#ifdef LIBPCRE
279 regex_t **probe = proto->data;
280 regmatch_t pos = { 0, len };
281
282 for (; *probe && regexec(*probe, p, 0, &pos, REG_STARTEND); probe++)
283 /* try them all */;
284
285 return (*probe != NULL);
286#else
287 /* Should never happen as we check when loading config file */
288 fprintf(stderr, "FATAL: regex probe called but not built in\n");
289 exit(5);
290#endif
291}
292
293/*
294 * Read the beginning of data coming from the client connection and check if
295 * it's a known protocol.
296 * Return PROBE_AGAIN if not enough data, or PROBE_MATCH if it succeeded in
297 * which case cnx->proto is set to the appropriate protocol.
298 */
299int probe_client_protocol(struct connection *cnx)
300{
301 char buffer[BUFSIZ];
302 struct proto *p;
303 int n;
304
305 n = read(cnx->q[0].fd, buffer, sizeof(buffer));
306 /* It's possible that read() returns an error, e.g. if the client
307 * disconnected between the previous call to select() and now. If that
308 * happens, we just connect to the default protocol so the caller of this
309 * function does not have to deal with a specific failure condition (the
310 * connection will just fail later normally). */
311 if (n > 0) {
312 int res = PROBE_NEXT;
313
314 defer_write(&cnx->q[1], buffer, n);
315
316 for (p = cnx->proto; p && res == PROBE_NEXT; p = p->next) {
317 if (! p->probe) continue;
318 if (verbose) fprintf(stderr, "probing for %s\n", p->description);
319
320 cnx->proto = p;
321 res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p);
322 }
323 if (res != PROBE_NEXT)
324 return res;
325 }
326
327 if (verbose)
328 fprintf(stderr,
329 "all probes failed, connecting to first protocol: %s\n",
330 protocols->description);
331
332 /* If none worked, return the first one affected (that's completely
333 * arbitrary) */
334 cnx->proto = protocols;
335 return PROBE_MATCH;
336}
337
338/* Returns the structure for specified protocol or NULL if not found */
339static struct proto* get_protocol(const char* description)
340{
341 int i;
342
343 for (i = 0; i < ARRAY_SIZE(builtins); i++) {
344 if (!strcmp(builtins[i].description, description)) {
345 return &builtins[i];
346 }
347 }
348 return NULL;
349}
350
351/* Returns the probe for specified protocol:
352 * parameter is the description in builtins[], or "regex"
353 * */
354T_PROBE* get_probe(const char* description) {
355 struct proto* p = get_protocol(description);
356
357 if (p)
358 return p->probe;
359
360 /* Special case of "regex" probe (we don't want to set it in builtins
361 * because builtins is also used to build the command-line options and
362 * regexp is not legal on the command line)*/
363 if (!strcmp(description, "regex"))
364 return regex_probe;
365
366 /* Special case of "sni" probe for same reason as above*/
367 if (!strcmp(description, "sni"))
368 return is_sni_protocol;
369
370 /* Special case of "timeout" is allowed as a probe name in the
371 * configuration file even though it's not really a probe */
372 if (!strcmp(description, "timeout"))
373 return is_true;
374
375 return NULL;
376}
377
378
379

Built with git-ssb-web