Branch data Line data Source code
1 : : // $Id: BackDoor.cc 6219 2008-10-01 05:39:07Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include "BackDoor.h"
8 : : #include "Event.h"
9 : : #include "Net.h"
10 : : #include "TCP.h"
11 : :
12 : 0 : BackDoorEndpoint::BackDoorEndpoint(TCP_Endpoint* e)
13 : : {
14 : 0 : endp = e;
15 : 0 : is_partial = 0;
16 : 0 : max_top_seq = 0;
17 : :
18 : 0 : rlogin_checking_done = 0;
19 : 0 : rlogin_string_separator_pos = 0;
20 : 0 : rlogin_num_null = 0;
21 : 0 : rlogin_slash_seen = 0;
22 : :
23 : : num_pkts = num_8k0_pkts = num_8k4_pkts =
24 : 0 : num_lines = num_normal_lines = num_bytes = num_7bit_ascii = 0;
25 : 0 : }
26 : :
27 : : #define NORMAL_LINE_LENGTH 80
28 : :
29 : : #define TELNET_IAC 255
30 : : #define IS_TELNET_NEGOTIATION_CMD(c) ((c) >= 251 && (c) <= 254)
31 : :
32 : : #define DEFAULT_MTU 512
33 : :
34 : : #define RLOGIN_MAX_SIGNATURE_LENGTH 256
35 : :
36 : 0 : void BackDoorEndpoint::FinalCheckForRlogin()
37 : : {
38 [ # # ]: 0 : if ( ! rlogin_checking_done )
39 : : {
40 : 0 : rlogin_checking_done = 1;
41 : :
42 [ # # ]: 0 : if ( rlogin_num_null > 0 )
43 : 0 : RloginSignatureFound(0);
44 : : }
45 : 0 : }
46 : :
47 : : int BackDoorEndpoint::DataSent(double /* t */, int seq,
48 : : int len, int caplen, const u_char* data,
49 : : const IP_Hdr* /* ip */,
50 : 0 : const struct tcphdr* /* tp */)
51 : : {
52 [ # # ]: 0 : if ( caplen < len )
53 : 0 : len = caplen;
54 : :
55 [ # # ]: 0 : if ( len <= 0 )
56 : 0 : return 0;
57 : :
58 [ # # ]: 0 : if ( endp->state == TCP_ENDPOINT_PARTIAL )
59 : 0 : is_partial = 1;
60 : :
61 : 0 : int ack = endp->AckSeq() - endp->StartSeq();
62 : 0 : int top_seq = seq + len;
63 : :
64 [ # # # # ]: 0 : if ( top_seq <= ack || top_seq <= max_top_seq )
65 : : // There is no new data in this packet.
66 : 0 : return 0;
67 : :
68 [ # # ]: 0 : if ( rlogin_signature_found )
69 : 0 : CheckForRlogin(seq, len, data);
70 : :
71 [ # # ]: 0 : if ( telnet_signature_found )
72 : 0 : CheckForTelnet(seq, len, data);
73 : :
74 [ # # ]: 0 : if ( ssh_signature_found )
75 : 0 : CheckForSSH(seq, len, data);
76 : :
77 [ # # ]: 0 : if ( ftp_signature_found )
78 : 0 : CheckForFTP(seq, len, data);
79 : :
80 [ # # ]: 0 : if ( root_backdoor_signature_found )
81 : 0 : CheckForRootBackdoor(seq, len, data);
82 : :
83 [ # # ]: 0 : if ( napster_signature_found )
84 : 0 : CheckForNapster(seq, len, data);
85 : :
86 [ # # ]: 0 : if ( gnutella_signature_found )
87 : 0 : CheckForGnutella(seq, len, data);
88 : :
89 [ # # ]: 0 : if ( kazaa_signature_found )
90 : 0 : CheckForKazaa(seq, len, data);
91 : :
92 [ # # ][ # # ]: 0 : if ( http_signature_found || http_proxy_signature_found )
[ # # ]
93 : 0 : CheckForHTTP(seq, len, data);
94 : :
95 [ # # ]: 0 : if ( smtp_signature_found )
96 : 0 : CheckForSMTP(seq, len, data);
97 : :
98 [ # # ]: 0 : if ( irc_signature_found )
99 : 0 : CheckForIRC(seq, len, data);
100 : :
101 [ # # ]: 0 : if ( gaobot_signature_found )
102 : 0 : CheckForGaoBot(seq, len, data);
103 : :
104 : 0 : max_top_seq = top_seq;
105 : :
106 : 0 : return 1;
107 : : }
108 : :
109 : 0 : RecordVal* BackDoorEndpoint::BuildStats()
110 : : {
111 : 0 : RecordVal* stats = new RecordVal(backdoor_endp_stats);
112 : :
113 : 0 : stats->Assign(0, new Val(is_partial, TYPE_BOOL));
114 : 0 : stats->Assign(1, new Val(num_pkts, TYPE_COUNT));
115 : 0 : stats->Assign(2, new Val(num_8k0_pkts, TYPE_COUNT));
116 : 0 : stats->Assign(3, new Val(num_8k4_pkts, TYPE_COUNT));
117 : 0 : stats->Assign(4, new Val(num_lines, TYPE_COUNT));
118 : 0 : stats->Assign(5, new Val(num_normal_lines, TYPE_COUNT));
119 : 0 : stats->Assign(6, new Val(num_bytes, TYPE_COUNT));
120 : 0 : stats->Assign(7, new Val(num_7bit_ascii, TYPE_COUNT));
121 : :
122 : 0 : return stats;
123 : : }
124 : :
125 : 0 : void BackDoorEndpoint::CheckForRlogin(int seq, int len, const u_char* data)
126 : : {
127 [ # # ]: 0 : if ( rlogin_checking_done )
128 : 0 : return;
129 : :
130 : : // Looking for pattern:
131 : : // <null>string<null>string<null>string/string<null>
132 : : // where all string's are non-empty 7-bit-ascii string
133 : : //
134 : : // To avoid having to reassemble, we keep testing each byte until
135 : : // one of the following happens:
136 : : //
137 : : // - A gap in sequence number occurs
138 : : // - Four null's have been found
139 : : // - The number of bytes we examined reaches RLOGIN_MAX_SIGNATURE_LENGTH
140 : : // - An empty or non-7-bit-ascii string is found
141 : : //
142 [ # # ]: 0 : if ( seq == 1 )
143 : : { // Check if first byte is a NUL.
144 [ # # ]: 0 : if ( data[0] == 0 )
145 : : {
146 : 0 : rlogin_num_null = 1;
147 : :
148 [ # # ]: 0 : if ( ! endp->IsOrig() )
149 : : {
150 : 0 : RloginSignatureFound(len);
151 : 0 : return;
152 : : }
153 : :
154 : 0 : rlogin_string_separator_pos = 1;
155 : :
156 : 0 : ++seq; // move past the byte
157 : 0 : ++data;
158 : 0 : --len;
159 : : }
160 : : else
161 : : {
162 : 0 : rlogin_checking_done = 1;
163 : 0 : return;
164 : : }
165 : : }
166 : :
167 [ # # ][ # # ]: 0 : if ( seq > max_top_seq && max_top_seq != 0 )
168 : : { // A gap! Since we don't reassemble things, stop now.
169 : 0 : RloginSignatureFound(0);
170 : 0 : return;
171 : : }
172 : :
173 [ # # ]: 0 : if ( seq + len <= max_top_seq )
174 : 0 : return; // nothing new
175 : :
176 [ # # ]: 0 : if ( seq < max_top_seq )
177 : : { // trim to just the new data
178 : 0 : int delta = max_top_seq - seq;
179 : 0 : seq += delta;
180 : 0 : data += delta;
181 : 0 : len -= delta;
182 : : }
183 : :
184 : : // Search for rlogin signature.
185 [ # # ][ # # ]: 0 : for ( int i = 0; i < len && rlogin_num_null < 4; ++i )
186 : : {
187 [ # # ]: 0 : if ( data[i] == 0 )
188 : : {
189 [ # # ]: 0 : if ( i + seq == rlogin_string_separator_pos + 1 )
190 : : { // Empty string found.
191 : 0 : rlogin_checking_done = 1;
192 : 0 : return;
193 : : }
194 : : else
195 : : {
196 : 0 : rlogin_string_separator_pos = i + seq;
197 : 0 : ++rlogin_num_null;
198 : : }
199 : : }
200 : :
201 [ # # ]: 0 : else if ( data[i] == '/' )
202 : : {
203 [ # # ]: 0 : if ( rlogin_num_null == 3 )
204 : : {
205 [ # # ]: 0 : if ( i + seq == rlogin_string_separator_pos + 1 )
206 : : { // Empty terminal type.
207 : 0 : rlogin_checking_done = 1;
208 : 0 : return;
209 : : }
210 : :
211 : 0 : rlogin_string_separator_pos = i + seq;
212 : 0 : rlogin_slash_seen = 1;
213 : : }
214 : : }
215 : :
216 [ # # ]: 0 : else if ( data[i] >= 128 )
217 : : { // Non-7-bit-ascii
218 : 0 : rlogin_checking_done = 1;
219 : 0 : return;
220 : : }
221 : : }
222 : :
223 [ # # ]: 0 : if ( rlogin_num_null == 4 )
224 : : {
225 [ # # ]: 0 : if ( rlogin_slash_seen )
226 : 0 : RloginSignatureFound(0);
227 : : else
228 : 0 : rlogin_checking_done = 1;
229 : :
230 : 0 : return;
231 : : }
232 : :
233 [ # # ]: 0 : if ( seq + len > RLOGIN_MAX_SIGNATURE_LENGTH )
234 : : { // We've waited for too long
235 : 0 : RloginSignatureFound(0);
236 : 0 : return;
237 : : }
238 : : }
239 : :
240 : 0 : void BackDoorEndpoint::RloginSignatureFound(int len)
241 : : {
242 [ # # ]: 0 : if ( rlogin_checking_done )
243 : 0 : return;
244 : :
245 : 0 : rlogin_checking_done = 1;
246 : :
247 : 0 : val_list* vl = new val_list;
248 : 0 : vl->append(endp->TCP()->BuildConnVal());
249 : 0 : vl->append(new Val(endp->IsOrig(), TYPE_BOOL));
250 : 0 : vl->append(new Val(rlogin_num_null, TYPE_COUNT));
251 : 0 : vl->append(new Val(len, TYPE_COUNT));
252 : :
253 : 0 : endp->TCP()->ConnectionEvent(rlogin_signature_found, vl);
254 : : }
255 : :
256 : 0 : void BackDoorEndpoint::CheckForTelnet(int /* seq */, int len, const u_char* data)
257 : : {
258 [ # # ][ # # ]: 0 : if ( len >= 3 &&
[ # # ][ # # ]
259 : : data[0] == TELNET_IAC && IS_TELNET_NEGOTIATION_CMD(data[1]) )
260 : : {
261 : 0 : TelnetSignatureFound(len);
262 : 0 : return;
263 : : }
264 : :
265 : : // Note, we do the analysis per-packet rather than on the reassembled
266 : : // stream. This is a lot more efficient as then we don't need to
267 : : // do stream reassembly; but it's potentially less accurate, and
268 : : // subject to evasion. *But*: backdoor detection is inherently
269 : : // subject to a wide variety of evasion, so allowing this form
270 : : // (which is a pain to exploit) costs little.
271 : :
272 : 0 : num_bytes += len;
273 : :
274 : 0 : int last_char = 0;
275 : 0 : int offset = 0; // where we consider the latest line to have begun
276 : 0 : int option_length = 0; // length of options in a line
277 : :
278 [ # # ]: 0 : for ( int i = 0; i < len; ++i )
279 : : {
280 : 0 : unsigned int c = data[i];
281 : :
282 [ # # ][ # # ]: 0 : if ( c == '\n' && last_char == '\r' )
283 : : {
284 : : // Compress CRLF to just one line termination.
285 : 0 : last_char = c;
286 : 0 : continue;
287 : : }
288 : :
289 [ # # ][ # # ]: 0 : if ( c == '\n' || c == '\r' )
290 : : {
291 : 0 : ++num_lines;
292 : :
293 [ # # ]: 0 : if ( i - offset - option_length <= NORMAL_LINE_LENGTH )
294 : 0 : ++num_normal_lines;
295 : :
296 : 0 : option_length = 0;
297 : 0 : offset = i;
298 : : }
299 : :
300 [ # # ]: 0 : else if ( c == TELNET_IAC )
301 : : {
302 : 0 : ++option_length;
303 : 0 : --num_bytes;
304 : :
305 [ # # ]: 0 : if ( ++i < len )
306 : : {
307 : 0 : unsigned int code = data[i];
308 [ # # ]: 0 : if ( code == TELNET_IAC )
309 : : // Escaped IAC.
310 : 0 : last_char = code;
311 : :
312 [ # # ][ # # ]: 0 : else if ( code >= 251 && code <= 254 )
313 : : { // 3-byte option: ignore next byte
314 : 0 : ++i;
315 : 0 : option_length += 2;
316 : 0 : num_bytes -= 2;
317 : : }
318 : :
319 : : else
320 : : // XXX: We don't deal with sub option for simplicity
321 : : // although we SHOULD!
322 : : {
323 : 0 : ++option_length;
324 : 0 : --num_bytes;
325 : : }
326 : : }
327 : 0 : continue;
328 : : }
329 : :
330 [ # # ][ # # ]: 0 : else if ( c != 0 && c < 128 )
331 : 0 : ++num_7bit_ascii;
332 : :
333 : 0 : last_char = c;
334 : : }
335 : : }
336 : :
337 : 0 : void BackDoorEndpoint::TelnetSignatureFound(int len)
338 : : {
339 : 0 : val_list* vl = new val_list;
340 : 0 : vl->append(endp->TCP()->BuildConnVal());
341 : 0 : vl->append(new Val(endp->IsOrig(), TYPE_BOOL));
342 : 0 : vl->append(new Val(len, TYPE_COUNT));
343 : :
344 : 0 : endp->TCP()->ConnectionEvent(telnet_signature_found, vl);
345 : 0 : }
346 : :
347 : 0 : void BackDoorEndpoint::CheckForSSH(int seq, int len, const u_char* data)
348 : : {
349 [ # # ][ # # ]: 0 : if ( seq == 1 && CheckForString("SSH-", data, len) && len > 4 &&
[ # # ][ # # ]
[ # # ][ # # ]
350 : : (data[4] == '1' || data[4] == '2') )
351 : : {
352 : 0 : SignatureFound(ssh_signature_found, 1);
353 : 0 : return;
354 : : }
355 : :
356 : : // Check for length pattern.
357 : :
358 [ # # ][ # # ]: 0 : if ( seq < max_top_seq || max_top_seq == 0 )
359 : : // Retransmission involved, or first pkt => size info useless.
360 : 0 : return;
361 : :
362 [ # # ]: 0 : if ( seq > max_top_seq )
363 : : { // Estimate number of packets in the sequence gap
364 : 0 : int gap = seq - max_top_seq;
365 : 0 : num_pkts += int((gap + DEFAULT_MTU - 1) / DEFAULT_MTU);
366 : : }
367 : :
368 : 0 : ++num_pkts;
369 : :
370 : : // According to the spec:
371 : : // SSH 1.x pkts have size 8k+4
372 : : // SSH 2.x pkts have size 8k >= 16 (most cipher blocks are 8n)
373 [ # # ]: 0 : if ( len <= 127 )
374 [ # # # ]: 0 : switch ( len & 7 ) {
375 : : case 0:
376 [ # # ]: 0 : if ( len >= 16 )
377 : 0 : ++num_8k0_pkts;
378 : 0 : break;
379 : :
380 : : case 4:
381 : 0 : ++num_8k4_pkts;
382 : : break;
383 : : }
384 : : else
385 : : { // len is likely to be some MTU.
386 : : }
387 : : }
388 : :
389 : 0 : void BackDoorEndpoint::CheckForRootBackdoor(int seq, int len, const u_char* data)
390 : : {
391 : : // Check for root backdoor signature: an initial payload of
392 : : // exactly "# ".
393 [ # # ][ # # ]: 0 : if ( seq == 1 && len == 2 && ! endp->IsOrig() &&
[ # # ][ # # ]
[ # # ][ # # ]
394 : : data[0] == '#' && data[1] == ' ' )
395 : 0 : SignatureFound(root_backdoor_signature_found);
396 : 0 : }
397 : :
398 : 0 : void BackDoorEndpoint::CheckForFTP(int seq, int len, const u_char* data)
399 : : {
400 : : // Check for FTP signature
401 : : //
402 : : // Currently, the signatures include: "220 ", "220-"
403 : : //
404 : : // For a day's worth of LBNL FTP activity (7,229 connections),
405 : : // the distribution of the code in the first line returned by
406 : : // the server (the lines always began with a code) is:
407 : : //
408 : : // 220: 6685
409 : : // 421: 535
410 : : // 226: 7
411 : : // 426: 1
412 : : // 200: 1
413 : : //
414 : : // The 421's are all "host does not have access" or "timeout" of
415 : : // some form, so it's not big deal with we miss them (if that helps
416 : : // keep down the false positives).
417 : :
418 [ # # ][ # # ]: 0 : if ( seq != 1 || endp->IsOrig() || len < 4 )
[ # # ][ # # ]
419 : 0 : return;
420 : :
421 [ # # ][ # # ]: 0 : if ( CheckForString("220", data, len) &&
[ # # ][ # # ]
422 : : (data[3] == ' ' || data[3] == '-') )
423 : 0 : SignatureFound(ftp_signature_found);
424 : :
425 [ # # ][ # # ]: 0 : else if ( CheckForString("421", data, len) &&
[ # # ][ # # ]
426 : : (data[3] == '-' || data[3] == ' ') )
427 : 0 : SignatureFound(ftp_signature_found);
428 : : }
429 : :
430 : 0 : void BackDoorEndpoint::CheckForNapster(int seq, int len, const u_char* data)
431 : : {
432 : : // Check for Napster signature "GETfoobar" or "SENDfoobar" where
433 : : // "foobar" is the Napster handle associated with the request
434 : : // (so pretty much any arbitrary identifier, but sent adjacent
435 : : // to the GET or SEND with no intervening whitespace; but also
436 : : // sent in a separate packet.
437 : :
438 [ # # ][ # # ]: 0 : if ( seq != 1 || ! endp->IsOrig() )
[ # # ]
439 : 0 : return;
440 : :
441 [ # # ][ # # ]: 0 : if ( len == 3 && CheckForString("GET", data, len) )
[ # # ]
442 : : // GETfoobar.
443 : 0 : SignatureFound(napster_signature_found);
444 : :
445 [ # # ][ # # ]: 0 : else if ( len == 4 && CheckForString("SEND", data, len) )
[ # # ]
446 : : // SENDfoobar.
447 : 0 : SignatureFound(napster_signature_found);
448 : : }
449 : :
450 : 0 : void BackDoorEndpoint::CheckForSMTP(int seq, int len, const u_char* data)
451 : : {
452 : 0 : const char* smtp_handshake[] = { "HELO", "EHLO", 0 };
453 : :
454 [ # # ]: 0 : if ( seq != 1 )
455 : 0 : return;
456 : :
457 [ # # ]: 0 : if ( CheckForStrings(smtp_handshake, data, len) )
458 : 0 : SignatureFound(smtp_signature_found);
459 : : }
460 : :
461 : 0 : void BackDoorEndpoint::CheckForIRC(int seq, int len, const u_char* data)
462 : : {
463 [ # # ][ # # ]: 0 : if ( seq != 1 || is_partial )
464 : 0 : return;
465 : :
466 : : const char* irc_indicator[] = {
467 : : "ERROR", "INVITE", "ISON", "JOIN", "KICK", "NICK",
468 : : "NJOIN", "NOTICE AUTH", "OPER", "PART", "PING", "PONG",
469 : : "PRIVMSG", "SQUERY", "SQUIT", "WHO", 0,
470 : 0 : };
471 : :
472 [ # # ]: 0 : if ( CheckForStrings(irc_indicator, data, len) )
473 : 0 : SignatureFound(irc_signature_found);
474 : : }
475 : :
476 : 0 : void BackDoorEndpoint::CheckForGnutella(int seq, int len, const u_char* data)
477 : : {
478 : : // After connecting to the server, the connecting client says:
479 : : //
480 : : // GNUTELLA CONNECT/<version>\n\n
481 : : //
482 : : // The accepting server responds:
483 : : //
484 : : // GNUTELLA OK\n\n
485 : : //
486 : : // We find checking the first 8 bytes suffices, and that will
487 : : // also catch variants that use something other than "CONNECT".
488 : :
489 [ # # ][ # # ]: 0 : if ( seq == 1 && CheckForString("GNUTELLA ", data, len) )
[ # # ]
490 : 0 : SignatureFound(gnutella_signature_found);
491 : 0 : }
492 : :
493 : 0 : void BackDoorEndpoint::CheckForGaoBot(int seq, int len, const u_char* data)
494 : : {
495 [ # # ][ # # ]: 0 : if ( seq == 1 && CheckForString("220 Bot Server (Win32)", data, len) )
[ # # ]
496 : 0 : SignatureFound(gaobot_signature_found);
497 : 0 : }
498 : :
499 : 0 : void BackDoorEndpoint::CheckForKazaa(int seq, int len, const u_char* data)
500 : : {
501 : : // *Some*, though not all, KaZaa connections begin with:
502 : : //
503 : : // GIVE<space>
504 : :
505 [ # # ][ # # ]: 0 : if ( seq == 1 && CheckForString("GIVE ", data, len) )
[ # # ]
506 : 0 : SignatureFound(kazaa_signature_found);
507 : 0 : }
508 : :
509 : :
510 : 0 : int is_http_whitespace(const u_char ch)
511 : : {
512 [ # # ][ # # ]: 0 : return ! isprint(ch) || isspace(ch);
513 : : }
514 : :
515 : 0 : int skip_http_whitespace(const u_char* data, int len, int max)
516 : : {
517 : : int k;
518 [ # # ]: 0 : for ( k = 0; k < len; ++k )
519 : : {
520 [ # # ]: 0 : if ( ! is_http_whitespace(data[k]) )
521 : 0 : break;
522 : :
523 : : // Here we do not go beyond CR -- this is OK for
524 : : // processing first line of HTTP requests. However, it
525 : : // cannot be used to process multiple-line headers.
526 : :
527 [ # # ][ # # ]: 0 : if ( data[k] == '\015' || k == max )
528 : 0 : return -1;
529 : : }
530 : :
531 [ # # ]: 0 : return k < len ? k : -1;
532 : : }
533 : :
534 : 0 : int is_absolute_url(const u_char* data, int len)
535 : : {
536 : : // Look for '://' in the URL.
537 : 0 : const char* abs_url_sig = "://";
538 : 0 : const char* abs_url_sig_pos = abs_url_sig;
539 : :
540 : : // Warning: the following code is NOT general for any signature string,
541 : : // but only works for specific strings like "://".
542 : :
543 [ # # ]: 0 : for ( int pos = 0; pos < len; ++pos )
544 : : {
545 [ # # ]: 0 : if ( *abs_url_sig_pos == '\0' )
546 : 0 : return 1;
547 : :
548 [ # # ]: 0 : if ( data[pos] == *abs_url_sig_pos )
549 : 0 : ++abs_url_sig_pos;
550 : :
551 : : else
552 : : {
553 [ # # ]: 0 : if ( is_http_whitespace(data[pos]) )
554 : 0 : return 0;
555 : :
556 : 0 : abs_url_sig_pos = abs_url_sig;
557 [ # # ][ # # ]: 0 : if ( *abs_url_sig != '\0' &&
558 : : *abs_url_sig_pos == data[pos] )
559 : 0 : ++abs_url_sig_pos;
560 : : }
561 : : }
562 : :
563 : 0 : return *abs_url_sig_pos == '\0';
564 : : }
565 : :
566 : 0 : void BackDoorEndpoint::CheckForHTTP(int seq, int len, const u_char* data)
567 : : {
568 : : // According to the RFC, we should look for
569 : : // '<method> SP <url> SP HTTP/<version> CR LF'
570 : : // where:
571 : : //
572 : : // <method> = GET | HEAD | POST
573 : : //
574 : : // (i.e., HTTP 1.1 methods are ignored for now)
575 : : // <version> = 1.0 | 1.1.
576 : : //
577 : : // However, this is probably too restrictive to catch 'non-standard'
578 : : // requests. Instead, we look for certain methods only in the first
579 : : // line of the first packet only.
580 : : //
581 : : // "The method is case-sensitive." -- RFC 2616
582 : :
583 : 0 : const char* http_method[] = { "GET", "HEAD", "POST", 0 };
584 : :
585 [ # # ]: 0 : if ( seq != 1 )
586 : 0 : return; // first packet only
587 : :
588 : : // Pick up the method.
589 : 0 : int pos = skip_http_whitespace (data, len, 0);
590 [ # # ]: 0 : if ( pos < 0 )
591 : 0 : return;
592 : :
593 : : int method;
594 [ # # ]: 0 : for ( method = 0; http_method[method]; ++method )
595 : : {
596 : 0 : const char* s = http_method[method];
597 : : int i;
598 [ # # ]: 0 : for ( i = pos; i < len; ++i, ++s )
599 [ # # ]: 0 : if ( data[i] != *s )
600 : 0 : break;
601 : :
602 [ # # ]: 0 : if ( *s == '\0' )
603 : : {
604 : 0 : pos = i;
605 : 0 : break;
606 : : }
607 : : }
608 : :
609 [ # # ]: 0 : if ( ! http_method[method] )
610 : 0 : return;
611 : :
612 [ # # ][ # # ]: 0 : if ( pos >= len || ! is_http_whitespace(data[pos]) )
[ # # ]
613 : 0 : return;
614 : :
615 [ # # ]: 0 : if ( http_signature_found )
616 : 0 : SignatureFound(http_signature_found);
617 : :
618 [ # # ]: 0 : if ( http_proxy_signature_found )
619 : : {
620 : 0 : const u_char* rest = data + pos;
621 : 0 : int rest_len = len - pos;
622 : :
623 : 0 : pos = skip_http_whitespace(rest, rest_len, rest_len);
624 : :
625 [ # # ]: 0 : if ( pos >= 0 )
626 : 0 : CheckForHTTPProxy(seq, rest_len - pos, rest + pos);
627 : : }
628 : : }
629 : :
630 : : void BackDoorEndpoint::CheckForHTTPProxy(int /* seq */, int len,
631 : 0 : const u_char* data)
632 : : {
633 : : // Proxy ONLY accepts absolute URI's: "The absoluteURI form is
634 : : // REQUIRED when the request is being made to a proxy." -- RFC 2616
635 : :
636 [ # # ]: 0 : if ( is_absolute_url(data, len) )
637 : 0 : SignatureFound(http_proxy_signature_found);
638 : 0 : }
639 : :
640 : :
641 : 0 : void BackDoorEndpoint::SignatureFound(EventHandlerPtr e, int do_orig)
642 : : {
643 : 0 : val_list* vl = new val_list;
644 : 0 : vl->append(endp->TCP()->BuildConnVal());
645 : :
646 [ # # ]: 0 : if ( do_orig )
647 : 0 : vl->append(new Val(endp->IsOrig(), TYPE_BOOL));
648 : :
649 : 0 : endp->TCP()->ConnectionEvent(e, vl);
650 : 0 : }
651 : :
652 : :
653 : : int BackDoorEndpoint::CheckForStrings(const char** strs,
654 : 0 : const u_char* data, int len)
655 : : {
656 [ # # ]: 0 : for ( ; *strs; ++strs )
657 [ # # ]: 0 : if ( CheckForFullString(*strs, data, len) )
658 : 0 : return 1;
659 : :
660 : 0 : return 0;
661 : : }
662 : :
663 : : int BackDoorEndpoint::CheckForFullString(const char* str,
664 : 0 : const u_char* data, int len)
665 : : {
666 [ # # ][ # # ]: 0 : for ( ; len > 0 && *str; --len, ++data, ++str )
667 [ # # ]: 0 : if ( *str != *data )
668 : 0 : return 0;
669 : :
670 : : // A "full" string means a non-prefix match.
671 [ # # ][ # # ]: 0 : return *str == 0 && (len == 0 || *data == ' ' || *data == '\t');
[ # # ][ # # ]
672 : : }
673 : :
674 : : int BackDoorEndpoint::CheckForString(const char* str,
675 : 0 : const u_char* data, int len)
676 : : {
677 [ # # ][ # # ]: 0 : for ( ; len > 0 && *str; --len, ++data, ++str )
678 [ # # ]: 0 : if ( *str != *data )
679 : 0 : return 0;
680 : :
681 : 0 : return *str == 0;
682 : : }
683 : :
684 : :
685 : 0 : BackDoor_Analyzer::BackDoor_Analyzer(Connection* c)
686 : 0 : : TCP_ApplicationAnalyzer(AnalyzerTag::Backdoor, c)
687 : : {
688 : 0 : orig_endp = resp_endp = 0;
689 : :
690 : 0 : orig_stream_pos = resp_stream_pos = 1;
691 : :
692 : 0 : timeout = backdoor_stat_period;
693 : 0 : backoff = backdoor_stat_backoff;
694 : :
695 : 0 : c->GetTimerMgr()->Add(new BackDoorTimer(network_time + timeout, this));
696 : 0 : }
697 : :
698 : 0 : BackDoor_Analyzer::~BackDoor_Analyzer()
699 : : {
700 : 0 : delete orig_endp;
701 : 0 : delete resp_endp;
702 [ # # ][ # # ]: 0 : }
[ # # ]
703 : :
704 : 0 : void BackDoor_Analyzer::Init()
705 : : {
706 : 0 : TCP_ApplicationAnalyzer::Init();
707 : :
708 [ # # ]: 0 : assert(TCP());
709 : 0 : orig_endp = new BackDoorEndpoint(TCP()->Orig());
710 : 0 : resp_endp = new BackDoorEndpoint(TCP()->Resp());
711 : 0 : }
712 : :
713 : : void BackDoor_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
714 : 0 : int seq, const IP_Hdr* ip, int caplen)
715 : : {
716 : 0 : Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);
717 : :
718 [ # # ]: 0 : if ( is_orig )
719 : 0 : orig_endp->DataSent(network_time, seq, len, caplen, data, 0, 0);
720 : : else
721 : 0 : resp_endp->DataSent(network_time, seq, len, caplen, data, 0, 0);
722 : 0 : }
723 : :
724 : 0 : void BackDoor_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
725 : : {
726 : 0 : Analyzer::DeliverStream(len, data, is_orig);
727 : :
728 [ # # ]: 0 : if ( is_orig )
729 : : {
730 : : orig_endp->DataSent(network_time, orig_stream_pos,
731 : 0 : len, len, data, 0, 0);
732 : 0 : orig_stream_pos += len;
733 : : }
734 : :
735 : : else
736 : : {
737 : : resp_endp->DataSent(network_time, resp_stream_pos,
738 : 0 : len, len, data, 0, 0);
739 : 0 : resp_stream_pos += len;
740 : : }
741 : 0 : }
742 : :
743 : 0 : void BackDoor_Analyzer::Done()
744 : : {
745 : 0 : TCP_ApplicationAnalyzer::Done();
746 : :
747 [ # # ]: 0 : if ( ! IsFinished() )
748 : : {
749 : 0 : orig_endp->FinalCheckForRlogin();
750 : 0 : resp_endp->FinalCheckForRlogin();
751 : :
752 [ # # ]: 0 : if ( ! TCP()->Skipping() )
753 : 0 : StatEvent();
754 : :
755 : 0 : RemoveEvent();
756 : : }
757 : :
758 : 0 : }
759 : :
760 : 0 : void BackDoor_Analyzer::StatTimer(double t, int is_expire)
761 : : {
762 [ # # ][ # # ]: 0 : if ( IsFinished() || TCP()->Skipping() )
[ # # ]
763 : 0 : return;
764 : :
765 : 0 : StatEvent();
766 : :
767 [ # # ]: 0 : if ( ! is_expire )
768 : : {
769 : 0 : timeout *= backoff;
770 : 0 : timer_mgr->Add(new BackDoorTimer(t + timeout, this));
771 : : }
772 : : }
773 : :
774 : 0 : void BackDoor_Analyzer::StatEvent()
775 : : {
776 : 0 : val_list* vl = new val_list;
777 : 0 : vl->append(TCP()->BuildConnVal());
778 : 0 : vl->append(orig_endp->BuildStats());
779 : 0 : vl->append(resp_endp->BuildStats());
780 : :
781 : 0 : TCP()->ConnectionEvent(backdoor_stats, vl);
782 : 0 : }
783 : :
784 : 0 : void BackDoor_Analyzer::RemoveEvent()
785 : : {
786 : 0 : val_list* vl = new val_list;
787 : 0 : vl->append(TCP()->BuildConnVal());
788 : :
789 : 0 : TCP()->ConnectionEvent(backdoor_remove_conn, vl);
790 : 0 : }
791 : :
792 : 0 : BackDoorTimer::BackDoorTimer(double t, BackDoor_Analyzer* a)
793 : 0 : : Timer(t, TIMER_BACKDOOR)
794 : : {
795 : 0 : analyzer = a;
796 : : // Make sure connection does not expire.
797 : 0 : Ref(a->Conn());
798 : 0 : }
799 : :
800 : 0 : BackDoorTimer::~BackDoorTimer()
801 : : {
802 : 0 : Unref(analyzer->Conn());
803 [ # # ][ # # ]: 0 : }
[ # # ]
804 : :
805 : 0 : void BackDoorTimer::Dispatch(double t, int is_expire)
806 : : {
807 : 0 : analyzer->StatTimer(t, is_expire);
808 [ + - ][ + - ]: 6 : }
|