git ssb

0+

cel / sslh



Tree: fecfb170c84cd6119165581a419a6545286f203a

Files: fecfb170c84cd6119165581a419a6545286f203a / probe.c

10713 bytesRaw
1/*
2# probe.c: Code for probing protocols
3#
4# Copyright (C) 2007-2012 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_tls_protocol(const char *p, int len, struct proto *proto)
221{
222 if (len < 3)
223 return PROBE_AGAIN;
224
225 /* TLS packet starts with a record "Hello" (0x16), followed by version
226 * (0x03 0x00-0x03) (RFC6101 A.1)
227 * This means we reject SSLv2 and lower, which is actually a good thing (RFC6176)
228 */
229 return p[0] == 0x16 && p[1] == 0x03 && ( p[2] >= 0 && p[2] <= 0x03);
230}
231
232static int is_adb_protocol(const char *p, int len, struct proto *proto)
233{
234 if (len < 30)
235 return PROBE_AGAIN;
236
237 /* The initial ADB host->device packet has a command type of CNXN, and a
238 * data payload starting with "host:". Note that current versions of the
239 * client hardcode "host::" (with empty serialno and banner fields) but
240 * other clients may populate those fields.
241 *
242 * We aren't checking amessage.data_length, under the assumption that
243 * a packet >= 30 bytes long will have "something" in the payload field.
244 */
245 return !memcmp(&p[0], "CNXN", 4) && !memcmp(&p[24], "host:", 5);
246}
247
248static int regex_probe(const char *p, int len, struct proto *proto)
249{
250#ifdef LIBPCRE
251 regex_t **probe = proto->data;
252 regmatch_t pos = { 0, len };
253
254 for (; *probe && regexec(*probe, p, 0, &pos, REG_STARTEND); probe++)
255 /* try them all */;
256
257 return (*probe != NULL);
258#else
259 /* Should never happen as we check when loading config file */
260 fprintf(stderr, "FATAL: regex probe called but not built in\n");
261 exit(5);
262#endif
263}
264
265/*
266 * Read the beginning of data coming from the client connection and check if
267 * it's a known protocol.
268 * Return PROBE_AGAIN if not enough data, or PROBE_MATCH if it succeeded in
269 * which case cnx->proto is set to the appropriate protocol.
270 */
271int probe_client_protocol(struct connection *cnx)
272{
273 char buffer[BUFSIZ];
274 struct proto *p;
275 int n;
276
277 n = read(cnx->q[0].fd, buffer, sizeof(buffer));
278 /* It's possible that read() returns an error, e.g. if the client
279 * disconnected between the previous call to select() and now. If that
280 * happens, we just connect to the default protocol so the caller of this
281 * function does not have to deal with a specific failure condition (the
282 * connection will just fail later normally). */
283 if (n > 0) {
284 int res = PROBE_NEXT;
285
286 defer_write(&cnx->q[1], buffer, n);
287
288 for (p = cnx->proto; p && res == PROBE_NEXT; p = p->next) {
289 if (! p->probe) continue;
290 if (verbose) fprintf(stderr, "probing for %s\n", p->description);
291
292 cnx->proto = p;
293 res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p);
294 }
295 if (res != PROBE_NEXT)
296 return res;
297 }
298
299 if (verbose)
300 fprintf(stderr,
301 "all probes failed, connecting to first protocol: %s\n",
302 protocols->description);
303
304 /* If none worked, return the first one affected (that's completely
305 * arbitrary) */
306 cnx->proto = protocols;
307 return PROBE_MATCH;
308}
309
310/* Returns the structure for specified protocol or NULL if not found */
311static struct proto* get_protocol(const char* description)
312{
313 int i;
314
315 for (i = 0; i < ARRAY_SIZE(builtins); i++) {
316 if (!strcmp(builtins[i].description, description)) {
317 return &builtins[i];
318 }
319 }
320 return NULL;
321}
322
323/* Returns the probe for specified protocol:
324 * parameter is the description in builtins[], or "regex"
325 * */
326T_PROBE* get_probe(const char* description) {
327 struct proto* p = get_protocol(description);
328
329 if (p)
330 return p->probe;
331
332 /* Special case of "regex" probe (we don't want to set it in builtins
333 * because builtins is also used to build the command-line options and
334 * regexp is not legal on the command line)*/
335 if (!strcmp(description, "regex"))
336 return regex_probe;
337
338 return NULL;
339}
340
341
342

Built with git-ssb-web