Branch data Line data Source code
1 : : // $Id:$
2 : : //
3 : : // This code contributed by Nadi Sarrar.
4 : :
5 : : #include "BitTorrentTracker.h"
6 : : #include "TCP_Reassembler.h"
7 : :
8 : : #include <sys/types.h>
9 : : #include <regex.h>
10 : :
11 : : # define FMT_INT "%lld"
12 : : # define FMT_UINT "%llu"
13 : :
14 : : static TableType* bt_tracker_headers = 0;
15 : : static RecordType* bittorrent_peer;
16 : : static TableType* bittorrent_peer_set;
17 : : static RecordType* bittorrent_benc_value;
18 : : static TableType* bittorrent_benc_dir;
19 : :
20 : 0 : BitTorrentTracker_Analyzer::BitTorrentTracker_Analyzer(Connection* c)
21 : 0 : : TCP_ApplicationAnalyzer(AnalyzerTag::BitTorrentTracker, c)
22 : : {
23 [ # # # # ]: 0 : if ( ! bt_tracker_headers )
24 : : {
25 : : bt_tracker_headers =
26 : 0 : internal_type("bt_tracker_headers")->AsTableType();
27 : : bittorrent_peer =
28 : 0 : internal_type("bittorrent_peer")->AsRecordType();
29 : : bittorrent_peer_set =
30 : 0 : internal_type("bittorrent_peer_set")->AsTableType();
31 : : bittorrent_benc_value =
32 : 0 : internal_type("bittorrent_benc_value")->AsRecordType();
33 : : bittorrent_benc_dir =
34 : 0 : internal_type("bittorrent_benc_dir")->AsTableType();
35 : : }
36 : :
37 : 0 : keep_alive = false;
38 : :
39 : 0 : req_state = BTT_REQ_GET;
40 : 0 : req_buf[sizeof(req_buf) - 1] = 0;
41 : 0 : req_buf_pos = req_buf;
42 : 0 : req_buf_len = 0;
43 : 0 : req_val_uri = 0;
44 : 0 : req_val_headers = new TableVal(bt_tracker_headers);
45 : :
46 : 0 : res_state = BTT_RES_STATUS;
47 : 0 : res_allow_blank_line = false;
48 : 0 : res_buf[sizeof(res_buf) - 1] = 0;
49 : 0 : res_buf_pos = res_buf;
50 : 0 : res_buf_len = 0;
51 : 0 : res_status = 0;
52 : 0 : res_val_headers = new TableVal(bt_tracker_headers);
53 : 0 : res_val_peers = new TableVal(bittorrent_peer_set);
54 : 0 : res_val_benc = new TableVal(bittorrent_benc_dir);
55 : :
56 : 0 : InitBencParser();
57 : :
58 : 0 : stop_orig = false;
59 : 0 : stop_resp = false;
60 : 0 : }
61 : :
62 : 0 : BitTorrentTracker_Analyzer::~BitTorrentTracker_Analyzer()
63 : : {
64 : 0 : Unref(req_val_uri);
65 : 0 : Unref(req_val_headers);
66 : :
67 : 0 : Unref(res_val_headers);
68 : 0 : Unref(res_val_peers);
69 : 0 : Unref(res_val_benc);
70 : :
71 : 0 : benc_stack.clear();
72 : 0 : benc_count.clear();
73 [ # # ][ # # ]: 0 : }
[ # # ]
74 : :
75 : 0 : void BitTorrentTracker_Analyzer::Done()
76 : : {
77 : 0 : TCP_ApplicationAnalyzer::Done();
78 : 0 : }
79 : :
80 : : void BitTorrentTracker_Analyzer::DeliverStream(int len, const u_char* data,
81 : 0 : bool orig)
82 : : {
83 : 0 : TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
84 : :
85 [ # # ]: 0 : assert(TCP());
86 : :
87 [ # # ]: 0 : if ( TCP()->IsPartial() )
88 : : // punt on partial.
89 : 0 : return;
90 : :
91 [ # # ]: 0 : if ( orig )
92 : 0 : ClientRequest(len, data);
93 : : else
94 : 0 : ServerReply(len, data);
95 : : }
96 : :
97 : 0 : void BitTorrentTracker_Analyzer::ClientRequest(int len, const u_char* data)
98 : : {
99 [ # # ]: 0 : if ( stop_orig )
100 : 0 : return;
101 : :
102 [ # # ]: 0 : if ( req_buf_len + len > sizeof(req_buf) - 1 )
103 : : {
104 : 0 : ProtocolViolation("BitTorrentTracker: request message too long");
105 : 0 : stop_orig = true;
106 : 0 : return;
107 : : }
108 : :
109 : 0 : memcpy(&req_buf[req_buf_len], data, len);
110 : 0 : req_buf_len += len;
111 : 0 : req_buf[req_buf_len] = 0;
112 : :
113 [ # # ]: 0 : while ( req_buf_pos < req_buf + req_buf_len )
114 : : {
115 : 0 : char* lf = strchr(req_buf_pos, '\n');
116 [ # # ]: 0 : if ( ! lf )
117 : 0 : break;
118 : 0 : *lf = 0;
119 : :
120 : 0 : char* cr = strrchr(req_buf_pos, '\r');
121 [ # # ]: 0 : if ( cr )
122 : 0 : *cr = 0;
123 : :
124 [ # # ]: 0 : if ( ! ParseRequest(req_buf_pos) )
125 : 0 : return;
126 : :
127 : 0 : req_buf_pos = lf + 1;
128 : :
129 [ # # ][ # # ]: 0 : if ( req_state == BTT_REQ_DONE && keep_alive )
130 : : {
131 : 0 : req_state = BTT_REQ_GET;
132 : 0 : req_buf_len -= (req_buf_pos - req_buf);
133 : 0 : memmove(req_buf, req_buf_pos, req_buf_len);
134 : 0 : req_buf_pos = req_buf;
135 : : req_val_headers =
136 : 0 : new TableVal(bt_tracker_headers);
137 : : }
138 : : }
139 : : }
140 : :
141 : 0 : void BitTorrentTracker_Analyzer::ServerReply(int len, const u_char* data)
142 : : {
143 [ # # ]: 0 : if ( stop_resp )
144 : 0 : return;
145 : :
146 [ # # ]: 0 : if ( res_state == BTT_RES_DONE )
147 : : // We are done already, i.e. state != 200.
148 : 0 : return;
149 : :
150 [ # # ]: 0 : if ( res_buf_len + len > sizeof(res_buf) - 1 )
151 : : {
152 : 0 : ProtocolViolation("BitTorrentTracker: response message too long");
153 : 0 : stop_resp = true;
154 : 0 : return;
155 : : }
156 : :
157 : 0 : memcpy(&res_buf[res_buf_len], data, len);
158 : 0 : res_buf_len += len;
159 : 0 : res_buf[res_buf_len] = 0;
160 : :
161 : 0 : while ( true )
162 : : {
163 [ # # ][ # # ]: 0 : while ( res_state != BTT_RES_BODY &&
164 : : res_buf_pos < res_buf + res_buf_len )
165 : : {
166 : 0 : char* lf = strchr(res_buf_pos, '\n');
167 [ # # ]: 0 : if ( ! lf )
168 : 0 : break;
169 : 0 : *lf = 0;
170 : :
171 : 0 : char* cr = strrchr(res_buf_pos, '\r');
172 [ # # ]: 0 : if ( cr )
173 : 0 : *cr = 0;
174 : :
175 [ # # ]: 0 : if ( ! ParseResponse(res_buf_pos) )
176 : 0 : return;
177 : :
178 : 0 : res_buf_pos = lf + 1;
179 : : }
180 : :
181 [ # # ][ # # ]: 0 : if ( res_state != BTT_RES_BODY ||
182 : : res_buf_pos >= res_buf + res_buf_len )
183 : 0 : break;
184 : :
185 : 0 : ResponseBody();
186 : :
187 [ # # # # ]: 0 : if ( res_state != BTT_RES_DONE ||
[ # # ]
188 : : res_status != 200 || ! keep_alive )
189 : 0 : break;
190 : :
191 : 0 : res_state = BTT_RES_STATUS;
192 : 0 : res_allow_blank_line = true;
193 : 0 : res_buf_len -= res_buf_pos - res_buf;
194 : 0 : memmove(res_buf, res_buf_pos, res_buf_len);
195 : 0 : res_buf_pos = res_buf;
196 : 0 : res_status = 0;
197 : :
198 : 0 : res_val_headers = new TableVal(bt_tracker_headers);
199 : 0 : res_val_peers = new TableVal(bittorrent_peer_set);
200 : 0 : res_val_benc = new TableVal(bittorrent_benc_dir);
201 : :
202 : 0 : InitBencParser();
203 : : }
204 : : }
205 : :
206 : 0 : void BitTorrentTracker_Analyzer::Undelivered(int seq, int len, bool orig)
207 : : {
208 : 0 : TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
209 : :
210 : 0 : ProtocolViolation("BitTorrentTracker: cannot recover from content gap");
211 : :
212 [ # # ]: 0 : if ( orig )
213 : 0 : stop_orig = true;
214 : : else
215 : 0 : stop_resp = true;
216 : 0 : }
217 : :
218 : 0 : void BitTorrentTracker_Analyzer::EndpointEOF(TCP_Reassembler* endp)
219 : : {
220 : 0 : TCP_ApplicationAnalyzer::EndpointEOF(endp);
221 : 0 : }
222 : :
223 : 0 : void BitTorrentTracker_Analyzer::InitBencParser(void)
224 : : {
225 : 0 : benc_stack.clear();
226 : 0 : benc_count.clear();
227 : :
228 : 0 : benc_state = BENC_STATE_EMPTY;
229 : 0 : benc_raw = 0;
230 : 0 : benc_raw_type = BENC_TYPE_NONE;
231 : 0 : benc_raw_len = 0;
232 : 0 : benc_key = 0;
233 : 0 : benc_key_len = 0;
234 : 0 : benc_strlen = 0;
235 : 0 : benc_str = 0;
236 : 0 : benc_str_len = 0;
237 : 0 : benc_str_have = 0;
238 : 0 : benc_int = 0;
239 : 0 : benc_int_val = 0;
240 : 0 : }
241 : :
242 : 0 : void BitTorrentTracker_Analyzer::DeliverWeird(const char* msg, bool orig)
243 : : {
244 [ # # ]: 0 : if ( bt_tracker_weird )
245 : : {
246 : 0 : val_list* vl = new val_list;
247 : 0 : vl->append(BuildConnVal());
248 : 0 : vl->append(new Val(orig, TYPE_BOOL));
249 : 0 : vl->append(new StringVal(msg));
250 : 0 : ConnectionEvent(bt_tracker_weird, vl);
251 : : }
252 : : else
253 : 0 : Weird(msg);
254 : 0 : }
255 : :
256 : 0 : bool BitTorrentTracker_Analyzer::ParseRequest(char* line)
257 : : {
258 : : static bool initialized = false;
259 : : static regex_t r_get, r_get_end, r_hdr;
260 : :
261 [ # # ]: 0 : if ( ! initialized )
262 : : {
263 : 0 : regcomp(&r_get, "^GET[ \t]+", REG_EXTENDED | REG_ICASE);
264 : : regcomp(&r_get_end, "[ \t]+HTTP/[0123456789.]+$",
265 : 0 : REG_EXTENDED | REG_ICASE);
266 : 0 : regcomp(&r_hdr, "^[^: \t]+:[ ]*", REG_EXTENDED | REG_ICASE);
267 : 0 : initialized = true;
268 : : }
269 : :
270 [ # # # # ]: 0 : switch ( req_state ) {
271 : : case BTT_REQ_GET:
272 : : {
273 : : regmatch_t match[1];
274 [ # # ]: 0 : if ( regexec(&r_get, line, 1, match, 0) )
275 : : {
276 : 0 : ProtocolViolation("BitTorrentTracker: invalid HTTP GET");
277 : 0 : stop_orig = true;
278 : 0 : return false;
279 : : }
280 : :
281 : : regmatch_t match_end[1];
282 [ # # ]: 0 : if ( ! regexec(&r_get_end, line, 1, match_end, 0) )
283 : : {
284 [ # # ]: 0 : if ( match_end[0].rm_so <= match[0].rm_eo )
285 : : {
286 : 0 : ProtocolViolation("BitTorrentTracker: invalid HTTP GET");
287 : 0 : stop_orig = true;
288 : 0 : return false;
289 : : }
290 : :
291 : 0 : keep_alive = (line[match_end[0].rm_eo - 1] == '1');
292 : 0 : line[match_end[0].rm_so] = 0;
293 : : }
294 : :
295 : 0 : RequestGet(&line[match[0].rm_eo]);
296 : :
297 : 0 : req_state = BTT_REQ_HEADER;
298 : : }
299 : 0 : break;
300 : :
301 : : case BTT_REQ_HEADER:
302 : : {
303 [ # # ]: 0 : if ( ! *line )
304 : : {
305 : 0 : EmitRequest();
306 : 0 : req_state = BTT_REQ_DONE;
307 : 0 : break;
308 : : }
309 : :
310 : : regmatch_t match[1];
311 [ # # ]: 0 : if ( regexec(&r_hdr, line, 1, match, 0) )
312 : : {
313 : 0 : ProtocolViolation("BitTorrentTracker: invalid HTTP request header");
314 : 0 : stop_orig = true;
315 : 0 : return false;
316 : : }
317 : :
318 : 0 : *strchr(line, ':') = 0; // this cannot fail - see regex_hdr
319 : 0 : RequestHeader(line, &line[match[0].rm_eo]);
320 : : }
321 : 0 : break;
322 : :
323 : : case BTT_REQ_DONE:
324 [ # # ]: 0 : if ( *line )
325 : : DeliverWeird(fmt("Got post request data: %s\n", line),
326 : 0 : true);
327 : : break;
328 : :
329 : : default:
330 : : // Make the compiler happy.
331 : : break;
332 : : }
333 : :
334 : 0 : return true;
335 : : }
336 : :
337 : 0 : void BitTorrentTracker_Analyzer::RequestGet(char* uri)
338 : : {
339 : 0 : req_val_uri = new StringVal(uri);
340 : 0 : }
341 : :
342 : 0 : void BitTorrentTracker_Analyzer::EmitRequest(void)
343 : : {
344 : : val_list* vl;
345 : :
346 : 0 : ProtocolConfirmation();
347 : :
348 : 0 : vl = new val_list;
349 : 0 : vl->append(BuildConnVal());
350 : 0 : vl->append(req_val_uri);
351 : 0 : vl->append(req_val_headers);
352 : :
353 : 0 : req_val_uri = 0;
354 : 0 : req_val_headers = 0;
355 : :
356 : 0 : ConnectionEvent(bt_tracker_request, vl);
357 : 0 : }
358 : :
359 : 0 : bool BitTorrentTracker_Analyzer::ParseResponse(char* line)
360 : : {
361 : : static bool initialized = false;
362 : : static regex_t r_stat, r_hdr;
363 : :
364 [ # # ]: 0 : if ( ! initialized )
365 : : {
366 : : regcomp(&r_stat, "^HTTP/[0123456789.]* ",
367 : 0 : REG_EXTENDED | REG_ICASE);
368 : 0 : regcomp(&r_hdr, "^[^: \t]+:[ ]*", REG_EXTENDED | REG_ICASE);
369 : 0 : initialized = true;
370 : : }
371 : :
372 [ # # # ]: 0 : switch ( res_state ) {
373 : : case BTT_RES_STATUS:
374 : : {
375 [ # # ][ # # ]: 0 : if ( res_allow_blank_line && ! *line )
376 : : {
377 : : // There may be an empty line after the bencoded
378 : : // directory, if this is a keep-alive connection.
379 : : // Ignore it.
380 : 0 : res_allow_blank_line = false;
381 : 0 : break;
382 : : }
383 : :
384 : : regmatch_t match[1];
385 [ # # ]: 0 : if ( regexec(&r_stat, line, 1, match, 0) )
386 : : {
387 : 0 : ProtocolViolation("BitTorrentTracker: invalid HTTP status");
388 : 0 : stop_resp = true;
389 : 0 : return false;
390 : : }
391 : :
392 : 0 : ResponseStatus(&line[match[0].rm_eo]);
393 : 0 : res_state = BTT_RES_HEADER;
394 : : }
395 : 0 : break;
396 : :
397 : : case BTT_RES_HEADER:
398 [ # # ]: 0 : if ( ! *line )
399 : : {
400 [ # # ]: 0 : if ( res_status != 200 )
401 : : {
402 : 0 : val_list* vl = new val_list;
403 : 0 : vl->append(BuildConnVal());
404 : 0 : vl->append(new Val(res_status, TYPE_COUNT));
405 : 0 : vl->append(res_val_headers);
406 : 0 : ConnectionEvent(bt_tracker_response_not_ok, vl);
407 : 0 : res_val_headers = 0;
408 : 0 : res_buf_pos = res_buf + res_buf_len;
409 : 0 : res_state = BTT_RES_DONE;
410 : : }
411 : : else
412 : 0 : res_state = BTT_RES_BODY;
413 : :
414 : 0 : break;
415 : : }
416 : :
417 : : {
418 : : regmatch_t match[1];
419 [ # # ]: 0 : if ( regexec(&r_hdr, line, 1, match, 0) )
420 : : {
421 : 0 : ProtocolViolation("BitTorrentTracker: invalid HTTP response header");
422 : 0 : stop_resp = true;
423 : 0 : return false;
424 : : }
425 : :
426 : 0 : *strchr(line, ':') = 0; // this cannot fail - see regex_hdr
427 : 0 : ResponseHeader(line, &line[match[0].rm_eo]);
428 : : }
429 : : break;
430 : :
431 : : default:
432 : : // Make the compiler happy.
433 : : break;
434 : : }
435 : :
436 : 0 : return true;
437 : : }
438 : :
439 : 0 : void BitTorrentTracker_Analyzer::ResponseStatus(char* status)
440 : : {
441 [ # # ]: 0 : if ( sscanf(status, FMT_UINT, &res_status) != 1 )
442 : 0 : res_status = 0;
443 : 0 : }
444 : :
445 : : void BitTorrentTracker_Analyzer::ParseHeader(char* name, char* value,
446 : 0 : bool is_request)
447 : : {
448 [ # # ]: 0 : if ( ! strcasecmp(name, "connection") )
449 : : {
450 [ # # ]: 0 : if ( ! strcasecmp(value, "close") )
451 : 0 : keep_alive = false;
452 : : else
453 : 0 : keep_alive = true;
454 : : }
455 : :
456 : : #ifdef BTTRACKER_STORE_HEADERS
457 : : StringVal* name_ = new StringVal(name);
458 : : StringVal* value_ = new StringVal(value);
459 : :
460 : : (is_request ? req_val_headers : res_val_headers)->Assign(name_, value_);
461 : : Unref(name_);
462 : : #endif
463 : 0 : }
464 : :
465 : : void BitTorrentTracker_Analyzer::ResponseBenc(int name_len, char* name,
466 : 0 : enum btt_benc_types type, int value_len, char* value)
467 : : {
468 [ # # ][ # # ]: 0 : if ( name_len == 5 && ! strncmp(name, "peers", 5) )
469 : : {
470 [ # # ]: 0 : for ( char* end = value + value_len; value < end; value += 6 )
471 : : {
472 : : // Note, weirdly/unfortunately AddrVal's take
473 : : // addresses in network order but PortVal's
474 : : // take ports in host order. BitTorrent specifies
475 : : // that both are in network order here.
476 : 0 : uint32 ad = extract_uint32((u_char*) value);
477 : 0 : uint16 pt = ntohs((value[4] << 8) | value[5]);
478 : :
479 : 0 : RecordVal* peer = new RecordVal(bittorrent_peer);
480 : 0 : peer->Assign(0, new AddrVal(ad));
481 : 0 : peer->Assign(1, new PortVal(pt, TRANSPORT_TCP));
482 : 0 : res_val_peers->Assign(peer, 0);
483 : :
484 : 0 : Unref(peer);
485 : : }
486 : : }
487 : : else
488 : : {
489 : 0 : StringVal* name_ = new StringVal(name_len, name);
490 : 0 : RecordVal* benc_value = new RecordVal(bittorrent_benc_value);
491 : 0 : benc_value->Assign(type, new StringVal(value_len, value));
492 : 0 : res_val_benc->Assign(name_, benc_value);
493 : :
494 : 0 : Unref(name_);
495 : : }
496 : 0 : }
497 : :
498 : : void BitTorrentTracker_Analyzer::ResponseBenc(int name_len, char* name,
499 : 0 : enum btt_benc_types type, bro_int_t value)
500 : : {
501 : 0 : RecordVal* benc_value = new RecordVal(bittorrent_benc_value);
502 : 0 : StringVal* name_ = new StringVal(name_len, name);
503 : :
504 : 0 : benc_value->Assign(type, new Val(value, TYPE_INT));
505 : 0 : res_val_benc->Assign(name_, benc_value);
506 : :
507 : 0 : Unref(name_);
508 : 0 : }
509 : :
510 : 0 : void BitTorrentTracker_Analyzer::ResponseBody(void)
511 : : {
512 [ # # ]: 0 : switch ( ResponseParseBenc() ) {
513 : : case 0:
514 : 0 : EmitResponse();
515 : 0 : res_state = BTT_RES_DONE;
516 : : break;
517 : :
518 : : case -1: // parsing failed
519 : : case -2: // need more data
520 : : break;
521 : : }
522 : 0 : }
523 : :
524 : 0 : int BitTorrentTracker_Analyzer::ResponseParseBenc(void)
525 : : {
526 : : #define VIOLATION_IF(expr, msg) \
527 : : { \
528 : : if ( expr ) \
529 : : { \
530 : : ProtocolViolation(msg); \
531 : : stop_resp = true; \
532 : : return -1; \
533 : : } \
534 : : }
535 : :
536 : : #define INC_COUNT \
537 : : { \
538 : : unsigned int count = benc_count.back(); \
539 : : benc_count.pop_back(); \
540 : : benc_count.push_back(count + 1); \
541 : : }
542 : :
543 [ # # ]: 0 : for ( unsigned int len = res_buf_len - (res_buf_pos - res_buf); len;
544 : : --len, ++res_buf_pos )
545 : : {
546 [ # # # # # : 0 : switch ( benc_state ) {
# # ]
547 : : case BENC_STATE_EMPTY:
548 : : {
549 [ # # # # # : 0 : switch ( res_buf_pos[0] ) {
# ]
550 : : case 'd':
551 [ # # # ]: 0 : switch ( benc_stack.size() ) {
552 : 0 : case 0: break;
553 : : case 1:
554 : 0 : benc_raw = res_buf_pos;
555 : 0 : benc_raw_type = BENC_TYPE_DIR;
556 : : /* fall through */
557 : : default:
558 [ # # ][ # # ]: 0 : VIOLATION_IF(benc_stack.back() == 'd' &&
[ # # ]
559 : : ! (benc_count.back() % 2),
560 : : "BitTorrentTracker: directory key is not a string but a directory")
561 : 0 : ++benc_raw_len;
562 : : }
563 : :
564 : 0 : benc_stack.push_back('d');
565 : 0 : benc_count.push_back(0);
566 : 0 : break;
567 : :
568 : : case 'l':
569 [ # # # ]: 0 : switch ( benc_stack.size() ) {
570 : : case 0:
571 : 0 : VIOLATION_IF(1, "BitTorrentTracker: not a bencoded directory (first char: l)")
572 : : /* fall through */
573 : :
574 : : case 1:
575 : 0 : benc_raw = res_buf_pos;
576 : 0 : benc_raw_type = BENC_TYPE_LIST;
577 : : /* fall through */
578 : :
579 : : default:
580 [ # # ][ # # ]: 0 : VIOLATION_IF(benc_stack.back() == 'd' &&
[ # # ]
581 : : ! (benc_count.back() % 2),
582 : : "BitTorrentTracker: directory key is not a string but a list")
583 : 0 : ++benc_raw_len;
584 : : }
585 : :
586 : 0 : benc_stack.push_back('l');
587 : 0 : benc_count.push_back(0);
588 : 0 : break;
589 : :
590 : : case 'i':
591 [ # # ]: 0 : VIOLATION_IF(! benc_stack.size(),
592 : : "BitTorrentTracker: not a bencoded directory (first char: i)")
593 [ # # ][ # # ]: 0 : VIOLATION_IF(benc_stack.back() == 'd' &&
[ # # ]
594 : : ! (benc_count.back() % 2),
595 : : "BitTorrentTracker: directory key is not a string but an int")
596 : :
597 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
598 : 0 : ++benc_raw_len;
599 : :
600 : 0 : benc_state = BENC_STATE_INT1;
601 : 0 : break;
602 : :
603 : : case 'e':
604 [ # # ]: 0 : VIOLATION_IF(! benc_stack.size(),
605 : : "BitTorrentTracker: not a bencoded directory (first char: e)")
606 [ # # ][ # # ]: 0 : VIOLATION_IF(benc_stack.back() == 'd' &&
[ # # ]
607 : : benc_count.back() % 2,
608 : : "BitTorrentTracker: directory has an odd count of members")
609 : :
610 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
611 : 0 : ++benc_raw_len;
612 : :
613 [ # # ]: 0 : if ( benc_stack.size() == 2 )
614 : : { // coming back to level 1
615 : : ResponseBenc(benc_key_len, benc_key,
616 : : benc_raw_type,
617 : 0 : benc_raw_len, benc_raw);
618 : 0 : benc_key = 0;
619 : 0 : benc_key_len = 0;
620 : 0 : benc_raw = 0;
621 : 0 : benc_raw_len = 0;
622 : 0 : benc_raw_type = BENC_TYPE_NONE;
623 : : }
624 : :
625 : 0 : benc_stack.pop_back();
626 : 0 : benc_count.pop_back();
627 : :
628 [ # # ]: 0 : if ( benc_stack.size() )
629 : 0 : INC_COUNT
630 : : else
631 : : { // benc parsing successful
632 : 0 : ++res_buf_pos;
633 : 0 : return 0;
634 : : }
635 : 0 : break;
636 : :
637 : : case '0': case '1': case '2': case '3': case '4':
638 : : case '5': case '6': case '7': case '8': case '9':
639 [ # # ]: 0 : VIOLATION_IF(! benc_stack.size(),
640 : : "BitTorrentTracker: not a bencoded directory (first char: [0-9])")
641 : :
642 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
643 : 0 : ++benc_raw_len;
644 : :
645 : 0 : benc_strlen = res_buf_pos;
646 : 0 : benc_state = BENC_STATE_STR1;
647 : 0 : break;
648 : :
649 : : default:
650 : 0 : VIOLATION_IF(1, "BitTorrentTracker: no valid bencoding")
651 : : }
652 : : }
653 : 0 : break;
654 : :
655 : : case BENC_STATE_INT1:
656 : 0 : benc_int = res_buf_pos;
657 [ # # ]: 0 : if ( res_buf_pos[0] == '-' )
658 : : {
659 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
660 : 0 : ++benc_raw_len;
661 : 0 : benc_state = BENC_STATE_INT2;
662 : 0 : break;
663 : : }
664 : :
665 : : case BENC_STATE_INT2:
666 [ # # ][ # # ]: 0 : VIOLATION_IF(res_buf_pos[0] < '0' ||
667 : : res_buf_pos[0] > '9',
668 : : "BitTorrentTracker: no valid bencoding")
669 : :
670 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
671 : 0 : ++benc_raw_len;
672 : :
673 : 0 : benc_state = BENC_STATE_INT3;
674 : 0 : break;
675 : :
676 : : case BENC_STATE_INT3:
677 [ # # ]: 0 : if ( res_buf_pos[0] == 'e' )
678 : : {
679 [ # # ]: 0 : if ( sscanf(benc_int, FMT_INT,
680 : : &benc_int_val) == 1 )
681 : : {
682 [ # # ]: 0 : if ( benc_stack.size() == 1 )
683 : : {
684 : : ResponseBenc(benc_key_len,
685 : : benc_key, BENC_TYPE_INT,
686 : 0 : benc_int_val);
687 : 0 : benc_key = 0;
688 : 0 : benc_key_len = 0;
689 : : }
690 : : }
691 : : else
692 : 0 : VIOLATION_IF(1, "BitTorrentTracker: no valid bencoding")
693 : :
694 : 0 : INC_COUNT
695 : 0 : benc_state = BENC_STATE_EMPTY;
696 : : }
697 : :
698 : : else
699 [ # # ][ # # ]: 0 : VIOLATION_IF(res_buf_pos[0] < '0' ||
700 : : res_buf_pos[0] > '9',
701 : : "BitTorrentTracker: no valid bencoding");
702 : :
703 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
704 : 0 : ++benc_raw_len;
705 : :
706 : 0 : break;
707 : :
708 : : case BENC_STATE_STR1:
709 [ # # # ]: 0 : switch ( res_buf_pos[0] ) {
710 : : case '0': case '1': case '2': case '3': case '4':
711 : : case '5': case '6': case '7': case '8': case '9':
712 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
713 : 0 : ++benc_raw_len;
714 : 0 : break;
715 : :
716 : : case ':':
717 [ # # ]: 0 : VIOLATION_IF(sscanf(benc_strlen, "%u",
718 : : &benc_str_len) != 1,
719 : : "BitTorrentTracker: no valid bencoding")
720 : :
721 : 0 : benc_str_have = 0;
722 : 0 : benc_str = res_buf_pos + 1;
723 : :
724 [ # # ][ # # ]: 0 : if ( benc_stack.size() == 1 &&
[ # # ]
725 : : ! (benc_count.front() % 2) )
726 : : {
727 : 0 : benc_key = benc_str;
728 : 0 : benc_key_len = benc_str_len;
729 : : }
730 : :
731 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
732 : 0 : ++benc_raw_len;
733 : :
734 : 0 : benc_state = BENC_STATE_STR2;
735 : 0 : break;
736 : :
737 : : default:
738 : 0 : VIOLATION_IF(1, "BitTorrentTracker: no valid bencoding")
739 : : }
740 : 0 : break;
741 : :
742 : : case BENC_STATE_STR2:
743 [ # # ]: 0 : if ( benc_str_have < benc_str_len )
744 : : {
745 : : unsigned int seek =
746 : 0 : min(len, benc_str_len - benc_str_have);
747 : 0 : benc_str_have += seek;
748 : :
749 [ # # ]: 0 : if ( benc_raw_type != BENC_TYPE_NONE )
750 : 0 : benc_raw_len += seek;
751 : :
752 : 0 : res_buf_pos += seek - 1;
753 : 0 : len -= seek - 1;
754 : : }
755 : :
756 [ # # ]: 0 : if ( benc_str_have == benc_str_len )
757 : : {
758 [ # # ][ # # ]: 0 : if ( benc_stack.size() == 1 && benc_key &&
[ # # ][ # # ]
759 : : benc_key != benc_str )
760 : : {
761 : : ResponseBenc(benc_key_len, benc_key,
762 : : BENC_TYPE_STR,
763 : 0 : benc_str_len, benc_str);
764 : 0 : benc_key_len = 0;
765 : 0 : benc_key = 0;
766 : : }
767 : :
768 [ # # ]: 0 : if ( ! benc_str_len )
769 : : {
770 : 0 : --res_buf_pos;
771 : 0 : ++len;
772 : : }
773 : :
774 : 0 : INC_COUNT
775 : 0 : benc_state = BENC_STATE_EMPTY;
776 : : }
777 : : break;
778 : : }
779 : : }
780 : :
781 : 0 : return -2; // need more data
782 : : }
783 : :
784 : 0 : void BitTorrentTracker_Analyzer::EmitResponse(void)
785 : : {
786 : 0 : ProtocolConfirmation();
787 : :
788 : 0 : val_list* vl = new val_list;
789 : 0 : vl->append(BuildConnVal());
790 : 0 : vl->append(new Val(res_status, TYPE_COUNT));
791 : 0 : vl->append(res_val_headers);
792 : 0 : vl->append(res_val_peers);
793 : 0 : vl->append(res_val_benc);
794 : :
795 : 0 : res_val_headers = 0;
796 : 0 : res_val_peers = 0;
797 : 0 : res_val_benc = 0;
798 : :
799 : 0 : ConnectionEvent(bt_tracker_response, vl);
800 [ + - ][ + - ]: 6 : }
|