Branch data Line data Source code
1 : : // $Id: TCP.cc 6916 2009-09-24 20:48:36Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : :
6 : : #include "Active.h"
7 : : #include "PIA.h"
8 : : #include "File.h"
9 : : #include "TCP.h"
10 : : #include "TCP_Reassembler.h"
11 : : #include "TCP_Rewriter.h"
12 : : #include "OSFinger.h"
13 : : #include "Event.h"
14 : :
15 : : namespace { // local namespace
16 : : const bool DEBUG_tcp_data_sent = false;
17 : : const bool DEBUG_tcp_connection_close = false;
18 : : }
19 : :
20 : : // The following are not included in all systems' tcp.h.
21 : :
22 : : #ifndef TH_ECE
23 : : #define TH_ECE 0x40
24 : : #endif
25 : :
26 : : #ifndef TH_CWR
27 : : #define TH_CWR 0x80
28 : : #endif
29 : :
30 : :
31 : : #define TOO_LARGE_SEQ_DELTA 1048576
32 : :
33 : : static const int ORIG = 1;
34 : : static const int RESP = 2;
35 : :
36 : 938 : TCP_Analyzer::TCP_Analyzer(Connection* conn)
37 : 938 : : TransportLayerAnalyzer(AnalyzerTag::TCP, conn)
38 : : {
39 : : // Set a timer to eventually time out this connection.
40 : 938 : ADD_ANALYZER_TIMER(&TCP_Analyzer::ExpireTimer,
41 : : network_time + tcp_SYN_timeout, 0,
42 : : TIMER_TCP_EXPIRE);
43 : :
44 : 938 : deferred_gen_event = close_deferred = 0;
45 : :
46 : 938 : seen_first_ACK = 0;
47 : 938 : is_active = 1;
48 : 938 : finished = 0;
49 : 938 : reassembling = 0;
50 : 938 : first_packet_seen = 0;
51 : 938 : src_pkt_writer = 0;
52 : :
53 : 938 : orig = new TCP_Endpoint(this, 1);
54 : 938 : resp = new TCP_Endpoint(this, 0);
55 : :
56 : 938 : orig->SetPeer(resp);
57 : 938 : resp->SetPeer(orig);
58 : :
59 [ - + # # ]: 938 : if ( dump_selected_source_packets )
60 : : {
61 [ # # ][ # # ]: 0 : if ( source_pkt_dump )
62 : : src_pkt_writer =
63 : 0 : new TCP_SourcePacketWriter(this, source_pkt_dump);
64 [ # # ][ # # ]: 0 : else if ( transformed_pkt_dump )
65 : : src_pkt_writer =
66 : 0 : new TCP_SourcePacketWriter(this, transformed_pkt_dump);
67 : : }
68 : 938 : }
69 : :
70 : 938 : TCP_Analyzer::~TCP_Analyzer()
71 : : {
72 [ - + ][ # # ]: 938 : LOOP_OVER_GIVEN_CHILDREN(i, packet_children)
[ # # ]
73 [ # # ][ # # ]: 0 : delete *i;
[ # # ]
74 : :
75 [ + - ][ # # ]: 938 : delete orig;
[ # # ]
76 [ + - ][ # # ]: 938 : delete resp;
[ # # ]
77 [ - + ][ # # ]: 938 : delete src_pkt_writer;
[ # # ]
78 [ + - ][ # # ]: 938 : }
[ # # ]
79 : :
80 : 938 : void TCP_Analyzer::Init()
81 : : {
82 : 938 : Analyzer::Init();
83 [ - + ]: 938 : LOOP_OVER_GIVEN_CHILDREN(i, packet_children)
84 : 0 : (*i)->Init();
85 : :
86 : : // Can't put this in construction because RewritingTrace() is virtual.
87 [ - + ][ # # ]: 938 : if ( transformed_pkt_dump && Conn()->RewritingTrace() )
[ - + ]
88 : : SetTraceRewriter(new TCP_Rewriter(this, transformed_pkt_dump,
89 : : transformed_pkt_dump_MTU,
90 : 0 : requires_trace_commitment));
91 : 938 : }
92 : :
93 : 938 : void TCP_Analyzer::Done()
94 : : {
95 : 938 : Analyzer::Done();
96 : :
97 [ + - + + ]: 938 : if ( connection_pending && is_active && ! BothClosed() )
[ + - ][ + + ]
98 : 500 : Event(connection_pending);
99 : :
100 [ - + ]: 938 : LOOP_OVER_GIVEN_CHILDREN(i, packet_children)
101 : 0 : (*i)->Done();
102 : :
103 : 938 : orig->Done();
104 : 938 : resp->Done();
105 : :
106 : 938 : finished = 1;
107 : 938 : }
108 : :
109 : 938 : void TCP_Analyzer::EnableReassembly()
110 : : {
111 : : SetReassembler(new TCP_Reassembler(this, this,
112 : : TCP_Reassembler::Forward, true, orig),
113 : : new TCP_Reassembler(this, this,
114 : 938 : TCP_Reassembler::Forward, false, resp));
115 : :
116 : 938 : reassembling = 1;
117 : :
118 [ - + ]: 938 : if ( new_connection_contents )
119 : 0 : Event(new_connection_contents);
120 : 938 : }
121 : :
122 : : void TCP_Analyzer::SetReassembler(TCP_Reassembler* rorig,
123 : 938 : TCP_Reassembler* rresp)
124 : : {
125 : 938 : orig->AddReassembler(rorig);
126 : 938 : rorig->SetDstAnalyzer(this);
127 : 938 : resp->AddReassembler(rresp);
128 : 938 : rresp->SetDstAnalyzer(this);
129 : :
130 : 938 : reassembling = 1;
131 : :
132 [ - + ]: 938 : if ( new_connection_contents )
133 : 0 : Event(new_connection_contents);
134 : 938 : }
135 : :
136 : : const struct tcphdr* TCP_Analyzer::ExtractTCP_Header(const u_char*& data,
137 : 17976 : int& len, int& caplen)
138 : : {
139 : 17976 : const struct tcphdr* tp = (const struct tcphdr*) data;
140 : 17976 : uint32 tcp_hdr_len = tp->th_off * 4;
141 : :
142 [ - + ]: 17976 : if ( tcp_hdr_len < sizeof(struct tcphdr) )
143 : : {
144 : 0 : Weird("bad_TCP_header_len");
145 : 0 : return 0;
146 : : }
147 : :
148 [ + - ][ - + ]: 17976 : if ( tcp_hdr_len > uint32(len) ||
149 : : sizeof(struct tcphdr) > uint32(caplen) )
150 : : {
151 : : // This can happen even with the above test, due to TCP
152 : : // options.
153 : 0 : Weird("truncated_header");
154 : 0 : return 0;
155 : : }
156 : :
157 : 17976 : len -= tcp_hdr_len; // remove TCP header
158 : 17976 : caplen -= tcp_hdr_len;
159 : 17976 : data += tcp_hdr_len;
160 : :
161 : 17976 : return tp;
162 : : }
163 : :
164 : : bool TCP_Analyzer::ValidateChecksum(const struct tcphdr* tp,
165 : 17976 : TCP_Endpoint* endpoint, int len, int caplen)
166 : : {
167 [ + - ][ + - ]: 17976 : if ( ! ignore_checksums && caplen >= len &&
[ - + ][ - + ]
168 : : ! endpoint->ValidChecksum(tp, len) )
169 : : {
170 : 0 : Weird("bad_TCP_checksum");
171 : 0 : endpoint->CheckHistory(HIST_CORRUPT_PKT, 'C');
172 : 0 : return false;
173 : : }
174 : : else
175 : 17976 : return true;
176 : : }
177 : :
178 : : void TCP_Analyzer::CheckFlagCombos(TCP_Flags flags, TCP_Endpoint* endpoint,
179 : 17976 : uint32 base_seq, int len, int dst_port)
180 : : {
181 : 17976 : bool is_orig = endpoint->IsOrig();
182 : :
183 [ + + + + ]: 17976 : if ( is_orig && ! (first_packet_seen & ORIG) )
184 [ + + ][ + + ]: 842 : is_partial = ! flags.SYN() || flags.ACK();
185 : :
186 [ + + ][ + + ]: 17976 : if ( ! is_orig && ! (first_packet_seen & RESP) && ! is_partial )
[ + + ]
187 : 711 : is_partial = ! flags.SYN();
188 : :
189 : : int bits_set = (flags.SYN() ? 1 : 0) + (flags.FIN() ? 1 : 0) +
190 [ + + ][ + + ]: 17976 : (flags.RST() ? 1 : 0);
[ + + ]
191 [ - + ]: 17976 : if ( bits_set > 1 )
192 : : {
193 [ # # ][ # # ]: 0 : if ( flags.FIN() && flags.RST() )
[ # # ]
194 : 0 : endpoint->CheckHistory(HIST_FIN_RST_PKT, 'I');
195 : : else
196 : 0 : endpoint->CheckHistory(HIST_MULTI_FLAG_PKT, 'Q');
197 : : }
198 : :
199 [ + + ]: 17976 : else if ( bits_set == 1 )
200 : : {
201 [ + + ]: 2319 : if ( flags.SYN() )
202 : : {
203 [ + + ]: 1042 : char code = flags.ACK() ? 'H' : 'S';
204 : :
205 [ + + ][ + + ]: 1042 : if ( endpoint->CheckHistory(HIST_SYN_PKT, code) &&
[ + + ]
206 : : base_seq != endpoint->hist_last_SYN )
207 : 24 : endpoint->AddHistory(code);
208 : :
209 : 1042 : endpoint->hist_last_SYN = base_seq;
210 : : }
211 : :
212 [ + + ]: 2319 : if ( flags.FIN() )
213 : : {
214 : : // For FIN's, the sequence number comes at the
215 : : // end of (any data in) the packet, not the
216 : : // beginning as for SYNs and RSTs.
217 [ + + ][ + + ]: 1096 : if ( endpoint->CheckHistory(HIST_FIN_PKT, 'F') &&
[ + + ]
218 : : base_seq + len != endpoint->hist_last_FIN )
219 : 66 : endpoint->AddHistory('F');
220 : :
221 : 1096 : endpoint->hist_last_FIN = base_seq + len;
222 : : }
223 : :
224 [ + + ]: 2319 : if ( flags.RST() )
225 : : {
226 [ + + ][ + + ]: 181 : if ( endpoint->CheckHistory(HIST_RST_PKT, 'R') &&
[ + + ]
227 : : base_seq != endpoint->hist_last_RST )
228 : 9 : endpoint->AddHistory('R');
229 : :
230 : 2319 : endpoint->hist_last_RST = base_seq;
231 : : }
232 : : }
233 : :
234 : : else
235 : : { // bits_set == 0
236 [ + + ]: 15657 : if ( len )
237 : 9042 : endpoint->CheckHistory(HIST_DATA_PKT, 'D');
238 : :
239 [ + - ]: 6615 : else if ( flags.ACK() )
240 : 6615 : endpoint->CheckHistory(HIST_ACK_PKT, 'A');
241 : : }
242 : 17976 : }
243 : :
244 : : void TCP_Analyzer::UpdateWindow(TCP_Endpoint* endpoint, unsigned int window,
245 : : uint32 base_seq, uint32 ack_seq,
246 : 17976 : TCP_Flags flags)
247 : : {
248 : : // Note, the offered window on an initial SYN is unscaled, even
249 : : // if the SYN includes scaling, so we need to do the following
250 : : // test *before* updating the scaling information below. (Hmmm,
251 : : // how does this work for windows on SYN/ACKs? ###)
252 : 17976 : int scale = endpoint->window_scale;
253 : 17976 : window = window << scale;
254 : :
255 : : // Don't analyze window values off of SYNs, they're sometimes
256 : : // immediately rescinded.
257 [ + + ]: 17976 : if ( ! flags.SYN() )
258 : : {
259 : : // ### Decide whether to accept new window based on Active
260 : : // Mapping policy.
261 [ + + ][ + + ]: 16934 : if ( int(base_seq - endpoint->window_seq) >= 0 &&
262 : : int(ack_seq - endpoint->window_ack_seq) >= 0 )
263 : : {
264 : 10511 : uint32 new_edge = ack_seq + window;
265 : 10511 : uint32 old_edge = endpoint->window_ack_seq + endpoint->window;
266 : 10511 : int advance = new_edge - old_edge;
267 : :
268 [ + + ]: 10511 : if ( advance < 0 )
269 : : {
270 : : // A window recision. We don't report these
271 : : // for FINs or RSTs, or if the connection
272 : : // has already been partially closed, since
273 : : // such recisions occur frequently in practice,
274 : : // probably as the receiver loses buffer memory
275 : : // due to its process going away.
276 : : //
277 : : // We also, for window scaling, allow a bit
278 : : // of slop ###. This is because sometimes
279 : : // there will be an apparent recision due
280 : : // to the granularity of the scaling.
281 [ + + ][ + + ]: 38 : if ( ! flags.FIN() && ! flags.RST() &&
[ + + ][ + - ]
[ - + ][ - + ]
282 : : endpoint->state != TCP_ENDPOINT_CLOSED &&
283 : : endpoint->state != TCP_ENDPOINT_RESET &&
284 : : (-advance) >= (1 << scale) )
285 : 0 : Weird("window_recision");
286 : : }
287 : :
288 : 10511 : endpoint->window = window;
289 : 10511 : endpoint->window_ack_seq = ack_seq;
290 : 10511 : endpoint->window_seq = base_seq;
291 : : }
292 : : }
293 : 17976 : }
294 : :
295 : : void TCP_Analyzer::ProcessSYN(const IP_Hdr* ip, const struct tcphdr* tp,
296 : : uint32 tcp_hdr_len, int& seq_len,
297 : : TCP_Endpoint* endpoint, TCP_Endpoint* peer,
298 : : uint32 base_seq, uint32 ack_seq,
299 : : const uint32* orig_addr,
300 : 1042 : int is_orig, TCP_Flags flags)
301 : : {
302 : 1042 : int len = seq_len;
303 : :
304 : 1042 : ++seq_len; // SYN consumes a byte of sequence space
305 : :
306 [ - + ]: 1042 : if ( flags.RST() )
307 : 0 : Weird("TCP_christmas");
308 : :
309 [ - + ]: 1042 : if ( flags.URG() )
310 : 0 : Weird("baroque_SYN");
311 : :
312 [ - + ]: 1042 : if ( len > 0 )
313 : : // T/TCP definitely complicates this.
314 : 0 : Weird("SYN_with_data");
315 : :
316 : 1042 : RecordVal* SYN_vals = BuildSYNPacketVal(is_orig, ip, tp)->AsRecordVal();
317 : :
318 : : // ### In the following, we could be fooled by an
319 : : // inconsistent SYN retransmission. Where's a normalizer
320 : : // when you need one?
321 : :
322 : : // ### We know that field 5 is the window scaling ....
323 : 1042 : int scale = int(SYN_vals->Lookup(5)->CoerceToInt());
324 : :
325 [ + + ]: 1042 : if ( scale < 0 )
326 : : { // no window scaling option
327 [ + + ]: 550 : if ( flags.ACK() )
328 : : { // window scaling not negotiated
329 : 83 : endpoint->window_scale = 0;
330 : 83 : peer->window_scale = 0;
331 : : }
332 : : else
333 : : // We're not offering window scaling.
334 : : // Ideally, we'd remember this fact so that
335 : : // if the SYN/ACK *does* include window
336 : : // scaling, we know it won't be negotiated.
337 : : // But it's a pain to track that, and hard
338 : : // to see how an adversarial responder could
339 : : // use it to evade. Also, if we *do* want
340 : : // to track it, we could do so using
341 : : // connection_SYN_packet.
342 : 550 : endpoint->window_scale = 0;
343 : : }
344 : : else
345 : : {
346 : 492 : endpoint->window_scale = scale;
347 : 492 : endpoint->window_seq = base_seq;
348 : 492 : endpoint->window_ack_seq = ack_seq;
349 : :
350 : 492 : peer->window_seq = ack_seq;
351 : 492 : peer->window_ack_seq = base_seq;
352 : : }
353 : :
354 [ - + ]: 1042 : if ( connection_SYN_packet )
355 : : {
356 : 0 : val_list* vl = new val_list;
357 : 0 : vl->append(BuildConnVal());
358 : 0 : vl->append(SYN_vals);
359 : 0 : ConnectionEvent(connection_SYN_packet, vl);
360 : : }
361 : : else
362 : 1042 : Unref(SYN_vals);
363 : :
364 : : // Passive fingerprinting.
365 : : //
366 : : // is_orig will be removed once we can do SYN-ACK fingerprinting.
367 [ - + ][ # # ]: 1042 : if ( OS_version_found && is_orig )
[ - + ]
368 : : {
369 : 0 : Val src_addr_val(orig_addr, TYPE_ADDR);
370 [ # # # # ]: 0 : if ( generate_OS_version_event->Size() == 0 ||
[ # # ]
371 : : generate_OS_version_event->Lookup(&src_addr_val) )
372 : : {
373 : : RecordVal* OS_val =
374 : 0 : BuildOSVal(is_orig, ip, tp, tcp_hdr_len);
375 [ # # ]: 0 : if ( OS_val )
376 : : { // found new OS version
377 : 0 : val_list* vl = new val_list;
378 : 0 : vl->append(BuildConnVal());
379 : 0 : vl->append(new AddrVal(orig_addr));
380 : 0 : vl->append(OS_val);
381 : 0 : ConnectionEvent(OS_version_found, vl);
382 : : }
383 : 0 : }
384 : : }
385 : 1042 : }
386 : :
387 : : void TCP_Analyzer::ProcessFIN(double t, TCP_Endpoint* endpoint,
388 : 1096 : int& seq_len, uint32 base_seq)
389 : : {
390 [ + + ]: 1096 : if ( endpoint->FIN_cnt == 0 )
391 : : {
392 : 937 : ++seq_len; // FIN consumes a byte of sequence space
393 : 937 : ++endpoint->FIN_cnt; // remember that we've seen a FIN
394 : : }
395 : :
396 [ + + ][ - + ]: 159 : else if ( t < endpoint->last_time + tcp_storm_interarrival_thresh &&
[ - + ]
397 : : ++endpoint->FIN_cnt == tcp_storm_thresh )
398 : 0 : Weird("FIN_storm");
399 : :
400 : : // Remember the relative seq in FIN_seq.
401 : 1096 : endpoint->FIN_seq = base_seq - endpoint->StartSeq() + seq_len;
402 : 1096 : }
403 : :
404 : : bool TCP_Analyzer::ProcessRST(double t, TCP_Endpoint* endpoint,
405 : : const IP_Hdr* ip, uint32 base_seq,
406 : 181 : int len, int& seq_len)
407 : : {
408 [ + + ][ - + ]: 181 : if ( t < endpoint->last_time + tcp_storm_interarrival_thresh &&
[ - + ]
409 : : ++endpoint->RST_cnt == tcp_storm_thresh )
410 : 0 : Weird("RST_storm");
411 : :
412 [ + + ]: 181 : else if ( endpoint->RST_cnt == 0 )
413 : 132 : ++endpoint->RST_cnt; // Remember we've seen a RST
414 : :
415 : : #ifdef ACTIVE_MAPPING
416 : : // if ( peer->state == TCP_ENDPOINT_INACTIVE )
417 : : // debug_msg("rst while inactive\n"); // ### Cold-start: what to do?
418 : : // else
419 : :
420 : : const NumericData* AM_policy;
421 : : get_map_result(ip->DstAddr4(), AM_policy);
422 : :
423 : : if ( base_seq == endpoint->AckSeq() )
424 : : ; // everyone should accept a RST in sequence
425 : :
426 : : else if ( endpoint->window == 0 )
427 : : ; // ### Cold Start: we don't know the window,
428 : : // so just go along for now
429 : :
430 : : else
431 : : {
432 : : uint32 right_edge = endpoint->AckSeq() +
433 : : (endpoint->window << endpoint->window_scale);
434 : :
435 : : if ( base_seq < right_edge )
436 : : {
437 : : if ( ! AM_policy->accepts_rst_in_window )
438 : : {
439 : : #if 0
440 : : debug_msg("Machine does not accept RST merely in window; ignoring. t=%.6f,base=%u, ackseq=%u, window=%hd \n",
441 : : network_time, base_seq, endpoint->AckSeq(), window);
442 : : #endif
443 : : return false;
444 : : }
445 : : }
446 : :
447 : : else if ( ! AM_policy->accepts_rst_outside_window )
448 : : {
449 : : #if 0
450 : : debug_msg("Machine does not accept RST outside window; ignoring. t=%.6f,base=%u, ackseq=%u, window=%hd \n",
451 : : network_time, base_seq, endpoint->AckSeq(), window);
452 : : #endif
453 : : return false;
454 : : }
455 : : }
456 : : #endif
457 : :
458 [ + + ]: 181 : if ( len > 0 )
459 : : {
460 : : // This now happens often enough that it's
461 : : // not in the least interesting.
462 : : // Weird("RST_with_data");
463 : :
464 : : // Don't include the data in the computation of
465 : : // the sequence space for this connection, as
466 : : // it's not in fact part of the TCP stream.
467 : 85 : seq_len = 0;
468 : : }
469 : :
470 : 181 : PacketWithRST();
471 : :
472 : 181 : return true;
473 : : }
474 : :
475 : : int TCP_Analyzer::ProcessFlags(double t,
476 : : const IP_Hdr* ip, const struct tcphdr* tp,
477 : : uint32 tcp_hdr_len, int len, int& seq_len,
478 : : TCP_Endpoint* endpoint, TCP_Endpoint* peer,
479 : : uint32 base_seq, uint32 ack_seq,
480 : : const uint32* orig_addr,
481 : 17976 : int is_orig, TCP_Flags flags)
482 : : {
483 [ + + ]: 17976 : if ( flags.SYN() )
484 : : ProcessSYN(ip, tp, tcp_hdr_len, seq_len, endpoint, peer,
485 : 1042 : base_seq, ack_seq, orig_addr, is_orig, flags);
486 : :
487 [ + + ]: 17976 : if ( flags.FIN() )
488 : 1096 : ProcessFIN(t, endpoint, seq_len, base_seq);
489 : :
490 [ + + ][ - + ]: 17976 : if ( flags.RST() &&
[ - + ]
491 : : ! ProcessRST(t, endpoint, ip, base_seq, len, seq_len) )
492 : 0 : return 0;
493 : :
494 [ + + ]: 17976 : if ( flags.ACK() )
495 : 17321 : ProcessACK(endpoint, peer, ack_seq, is_orig, flags);
496 : :
497 : 17976 : return 1;
498 : : }
499 : :
500 : : void TCP_Analyzer::TransitionFromInactive(double t, TCP_Endpoint* endpoint,
501 : : uint32 base_seq,
502 : 1732 : uint32 last_seq, int SYN)
503 : : {
504 [ + + ]: 1732 : if ( SYN )
505 : : {
506 : : // ## endpoint->AckSeq() = endpoint->start_seq = base_seq;
507 : 989 : endpoint->InitAckSeq(base_seq);
508 : 989 : endpoint->InitStartSeq(base_seq);
509 : : }
510 : : else
511 : : {
512 : : // This is a partial connection - set up the
513 : : // initial sequence numbers as though we saw
514 : : // a SYN, to keep the relative byte numbering
515 : : // consistent.
516 : : // ## endpoint->AckSeq() = endpoint->start_seq = base_seq - 1;
517 : 743 : endpoint->InitAckSeq(base_seq - 1);
518 : 743 : endpoint->InitStartSeq(base_seq - 1);
519 : : }
520 : :
521 : : // ## endpoint->last_seq = last_seq;
522 : 1732 : endpoint->InitLastSeq(last_seq);
523 : 1732 : endpoint->start_time = t;
524 : 1732 : }
525 : :
526 : : int TCP_Analyzer::UpdateLastSeq(TCP_Endpoint* endpoint, uint32 last_seq,
527 : 17976 : TCP_Flags flags)
528 : : {
529 : 17976 : int delta_last = seq_delta(last_seq, endpoint->LastSeq());
530 : :
531 [ + + + + ]: 17976 : if ( (flags.SYN() || flags.RST()) &&
[ + + ][ + + ]
[ + + ]
532 : : (delta_last > TOO_LARGE_SEQ_DELTA ||
533 : : delta_last < -TOO_LARGE_SEQ_DELTA) )
534 : : // ### perhaps trust RST seq #'s if initial and not too
535 : : // outlandish, but not if they're coming after the other
536 : : // side has sent a FIN - trust the FIN ack instead
537 : : ;
538 : :
539 [ + + ][ + + ]: 17946 : else if ( flags.FIN() &&
[ + + ]
540 : : endpoint->LastSeq() == endpoint->StartSeq() + 1 )
541 : : // Update last_seq based on the FIN even if delta_last < 0.
542 : : // This is to accommodate > 2 GB connections for which
543 : : // we've only seen the SYN and the FIN (hence the check
544 : : // for last_seq == start_seq + 1).
545 : 67 : endpoint->UpdateLastSeq(last_seq);
546 : :
547 [ + + ]: 17879 : else if ( endpoint->state == TCP_ENDPOINT_RESET )
548 : : // don't trust any subsequent sequence numbers
549 : : ;
550 : :
551 [ + + ]: 17864 : else if ( delta_last > 0 )
552 : : // ### check for large jumps here.
553 : : // ## endpoint->last_seq = last_seq;
554 : 9142 : endpoint->UpdateLastSeq(last_seq);
555 : :
556 : : else if ( delta_last <= 0 )
557 : : { // ### ++retransmit, unless this is a pure ack
558 : : }
559 : :
560 : 17976 : return delta_last;
561 : : }
562 : :
563 : : void TCP_Analyzer::ProcessACK(TCP_Endpoint* endpoint, TCP_Endpoint* peer,
564 : : uint32 ack_seq, int is_orig,
565 : 17321 : TCP_Flags flags)
566 : : {
567 [ + + ][ + + ]: 17321 : if ( is_orig && ! seen_first_ACK &&
[ + + ][ + + ]
568 : : (endpoint->state == TCP_ENDPOINT_ESTABLISHED ||
569 : : endpoint->state == TCP_ENDPOINT_SYN_SENT) )
570 : : {
571 : 453 : seen_first_ACK = 1;
572 : 453 : Event(connection_first_ACK);
573 : : }
574 : :
575 [ + + ]: 17321 : if ( peer->state == TCP_ENDPOINT_INACTIVE )
576 : : {
577 [ + + ][ + + ]: 797 : if ( ! flags.SYN() && ! flags.FIN() && ! flags.RST() )
[ + + ][ + + ]
578 : : {
579 [ + + ][ + - ]: 565 : if ( endpoint->state == TCP_ENDPOINT_SYN_SENT ||
[ - + ]
580 : : endpoint->state == TCP_ENDPOINT_SYN_ACK_SENT ||
581 : : endpoint->state == TCP_ENDPOINT_ESTABLISHED )
582 : : {
583 : : // We've already sent a SYN, but that
584 : : // hasn't roused the other end, yet we're
585 : : // ack'ing their data.
586 : :
587 [ + + ]: 3 : if ( ! Conn()->DidWeird() )
588 : 1 : Weird("possible_split_routing");
589 : : }
590 : : }
591 : :
592 : : // Start the sequence numbering as if there was an initial
593 : : // SYN, so the relative numbering of subsequent data packets
594 : : // stays consistent.
595 : : // ## peer->start_seq = peer->AckSeq() = peer->last_seq =
596 : : // ## ack_seq - 1;
597 : 797 : peer->InitStartSeq(ack_seq - 1);
598 : 797 : peer->InitAckSeq(ack_seq - 1);
599 : 797 : peer->InitLastSeq(ack_seq - 1);
600 : : }
601 : :
602 [ + + ]: 16524 : else if ( ! flags.RST() )
603 : : { // don't trust ack's in RST packets
604 : 16518 : int delta_ack = seq_delta(ack_seq, peer->AckSeq());
605 [ - + # # ]: 16518 : if ( ack_seq == 0 && delta_ack > TOO_LARGE_SEQ_DELTA )
606 : : // More likely that this is a broken ack than a
607 : : // large connection that happens to land on 0 in the
608 : : // sequence space.
609 : : ;
610 : :
611 [ + + ]: 16518 : else if ( delta_ack > 0 )
612 : 7355 : peer->UpdateAckSeq(ack_seq);
613 : : }
614 : :
615 : 17321 : peer->AckReceived(ack_seq - peer->StartSeq());
616 : 17321 : }
617 : :
618 : : void TCP_Analyzer::UpdateInactiveState(double t,
619 : : TCP_Endpoint* endpoint, TCP_Endpoint* peer,
620 : : uint32 base_seq, uint32 ack_seq,
621 : : int len, int is_orig, TCP_Flags flags,
622 : 1732 : int& do_close, int& gen_event)
623 : : {
624 [ + + ]: 1732 : if ( flags.SYN() )
625 : : {
626 [ + + ]: 989 : if ( is_orig )
627 : : {
628 [ + + ]: 479 : if ( flags.ACK() )
629 : : {
630 : 2 : Weird("connection_originator_SYN_ack");
631 : 2 : endpoint->SetState(TCP_ENDPOINT_SYN_ACK_SENT);
632 : : }
633 : : else
634 : 477 : endpoint->SetState(TCP_ENDPOINT_SYN_SENT);
635 : :
636 [ + - ]: 479 : if ( connection_attempt )
637 : 479 : ADD_ANALYZER_TIMER(&TCP_Analyzer::AttemptTimer,
638 : : t + tcp_attempt_delay, 1,
639 : : TIMER_TCP_ATTEMPT);
640 : : }
641 : : else
642 : : {
643 [ + - ]: 510 : if ( flags.ACK() )
644 : : {
645 [ + + ][ + - ]: 510 : if ( peer->state != TCP_ENDPOINT_INACTIVE &&
[ + + ][ + + ]
646 : : peer->state != TCP_ENDPOINT_PARTIAL &&
647 : : ! seq_between(ack_seq, peer->StartSeq(), peer->LastSeq()) )
648 : 510 : Weird("bad_SYN_ack");
649 : : }
650 : :
651 [ # # ][ # # ]: 0 : else if ( peer->state == TCP_ENDPOINT_SYN_ACK_SENT &&
[ # # ]
652 : : base_seq == endpoint->StartSeq() )
653 : : {
654 : : // This is a SYN/SYN-ACK reversal,
655 : : // per the discussion in IsReuse.
656 : : // Flip the endpoints and establish
657 : : // the connection.
658 : 0 : Conn()->FlipRoles();
659 : 0 : peer->SetState(TCP_ENDPOINT_ESTABLISHED);
660 : : }
661 : :
662 : : else
663 : 0 : Weird("simultaneous_open");
664 : :
665 [ + + ]: 510 : if ( peer->state == TCP_ENDPOINT_SYN_SENT )
666 : 448 : peer->SetState(TCP_ENDPOINT_ESTABLISHED);
667 [ + - ]: 62 : else if ( peer->state == TCP_ENDPOINT_INACTIVE )
668 : : {
669 : : // If we were to ignore SYNs and
670 : : // only instantiate state on SYN
671 : : // acks, then we'd do:
672 : : // peer->SetState(TCP_ENDPOINT_ESTABLISHED);
673 : : // here.
674 : 62 : Weird("unsolicited_SYN_response");
675 : : }
676 : :
677 : 510 : endpoint->SetState(TCP_ENDPOINT_ESTABLISHED);
678 : :
679 [ + - ]: 510 : if ( peer->state != TCP_ENDPOINT_PARTIAL )
680 : : {
681 : 510 : Event(connection_established);
682 : 510 : Conn()->EnableStatusUpdateTimer();
683 : : }
684 : : }
685 : : }
686 : :
687 [ + + ]: 1732 : if ( flags.FIN() )
688 : : {
689 : 144 : endpoint->SetState(TCP_ENDPOINT_CLOSED);
690 : 144 : do_close = gen_event = 1;
691 [ + + + - ]: 144 : if ( peer->state != TCP_ENDPOINT_PARTIAL && ! flags.SYN() )
[ + + ]
692 : 136 : Weird("spontaneous_FIN");
693 : : }
694 : :
695 [ + + ]: 1732 : if ( flags.RST() )
696 : : {
697 : 80 : endpoint->SetState(TCP_ENDPOINT_RESET);
698 : :
699 : 80 : int is_reject = 0;
700 : :
701 [ + + ]: 80 : if ( is_orig )
702 : : {
703 : : // If our peer is established then we saw
704 : : // a SYN-ack but not SYN - so a reverse
705 : : // scan, and we should treat this as a
706 : : // reject.
707 [ - + ]: 14 : if ( peer->state == TCP_ENDPOINT_ESTABLISHED )
708 : 14 : is_reject = 1;
709 : : }
710 : :
711 [ + + ][ - + ]: 66 : else if ( peer->state == TCP_ENDPOINT_SYN_SENT ||
712 : : peer->state == TCP_ENDPOINT_SYN_ACK_SENT )
713 : : // We're rejecting an initial SYN.
714 : 4 : is_reject = 1;
715 : :
716 : 80 : do_close = 1;
717 : 80 : gen_event = ! is_reject;
718 : :
719 [ + + ]: 80 : if ( is_reject )
720 : 4 : Event(connection_rejected);
721 : :
722 [ + + ]: 76 : else if ( peer->state == TCP_ENDPOINT_INACTIVE )
723 : 34 : Weird("spontaneous_RST");
724 : : }
725 : :
726 [ + + ]: 1732 : if ( endpoint->state == TCP_ENDPOINT_INACTIVE )
727 : : { // No control flags to change the state.
728 [ + + ][ + + ]: 519 : if ( ! is_orig && len == 0 &&
[ + + ]
729 : : orig->state == TCP_ENDPOINT_SYN_SENT )
730 : : // Some eccentric TCP's will ack an initial
731 : : // SYN prior to sending a SYN reply (hello,
732 : : // ftp.microsoft.com). For those, don't
733 : : // consider the ack as forming a partial
734 : : // connection.
735 : : ;
736 : : else
737 : : {
738 : 508 : endpoint->SetState(TCP_ENDPOINT_PARTIAL);
739 : 508 : Conn()->EnableStatusUpdateTimer();
740 : :
741 [ + + ]: 508 : if ( peer->state == TCP_ENDPOINT_PARTIAL )
742 : : // We've seen both sides of a partial
743 : : // connection, report it.
744 : 149 : Event(partial_connection);
745 : : }
746 : : }
747 : 1732 : }
748 : :
749 : : void TCP_Analyzer::UpdateSYN_SentState(double t,
750 : : TCP_Endpoint* endpoint, TCP_Endpoint* peer,
751 : : uint32 base_seq, uint32 last_seq,
752 : : int len, int is_orig, TCP_Flags flags,
753 : 396 : int& do_close, int& gen_event)
754 : : {
755 [ - + ]: 396 : if ( flags.SYN() )
756 : : {
757 [ # # ]: 0 : if ( is_orig )
758 : : {
759 [ # # ][ # # ]: 0 : if ( flags.ACK() && ! flags.FIN() && ! flags.RST() &&
[ # # ][ # # ]
[ # # ]
760 : : endpoint->state != TCP_ENDPOINT_SYN_ACK_SENT )
761 : 0 : Weird("repeated_SYN_with_ack");
762 : : }
763 : : else
764 : : {
765 [ # # ][ # # ]: 0 : if ( ! flags.ACK() &&
[ # # ]
766 : : endpoint->state != TCP_ENDPOINT_SYN_SENT )
767 : 0 : Weird("repeated_SYN_reply_wo_ack");
768 : : }
769 : :
770 [ # # ]: 0 : if ( base_seq != endpoint->StartSeq() )
771 : : {
772 : 0 : Weird("SYN_seq_jump");
773 : : // ## endpoint->AckSeq() = endpoint->start_seq = base_seq;
774 : : // ## endpoint->last_seq = last_seq;
775 : 0 : endpoint->InitStartSeq(base_seq);
776 : 0 : endpoint->InitAckSeq(base_seq);
777 : 0 : endpoint->InitLastSeq(last_seq);
778 : : }
779 : : }
780 : :
781 [ + + ]: 396 : if ( flags.FIN() )
782 : : {
783 [ + - ][ - + ]: 7 : if ( peer->state == TCP_ENDPOINT_INACTIVE ||
784 : : peer->state == TCP_ENDPOINT_SYN_SENT )
785 : 0 : Weird("inappropriate_FIN");
786 : :
787 : 7 : endpoint->SetState(TCP_ENDPOINT_CLOSED);
788 : 7 : do_close = gen_event = 1;
789 : : }
790 : :
791 [ - + ]: 396 : if ( flags.RST() )
792 : : {
793 : 0 : endpoint->SetState(TCP_ENDPOINT_RESET);
794 : 0 : ConnectionReset();
795 : 0 : do_close = 1;
796 : : }
797 : :
798 [ + + ]: 396 : else if ( len > 0 )
799 : 67 : Weird("data_before_established");
800 : 396 : }
801 : :
802 : : void TCP_Analyzer::UpdateEstablishedState(double t,
803 : : TCP_Endpoint* endpoint, TCP_Endpoint* peer,
804 : : uint32 base_seq, uint32 last_seq,
805 : : int is_orig, TCP_Flags flags,
806 : 15073 : int& do_close, int& gen_event)
807 : : {
808 [ + + ]: 15073 : if ( flags.SYN() )
809 : : {
810 [ - + ][ # # ]: 53 : if ( endpoint->state == TCP_ENDPOINT_PARTIAL &&
[ # # ][ - + ]
811 : : peer->state == TCP_ENDPOINT_INACTIVE && ! flags.ACK() )
812 : : {
813 : 0 : Weird("SYN_after_partial");
814 : 0 : endpoint->SetState(TCP_ENDPOINT_SYN_SENT);
815 : : }
816 : :
817 [ - + ]: 53 : if ( endpoint->Size() > 0 )
818 : 0 : Weird("SYN_inside_connection");
819 : :
820 [ + + ]: 53 : if ( base_seq != endpoint->StartSeq() )
821 : 24 : Weird("SYN_seq_jump");
822 : :
823 : : // Make a guess that somehow the connection didn't
824 : : // get established, and this SYN will be the
825 : : // one that actually sets it up.
826 : : // ## endpoint->AckSeq() = endpoint->start_seq = base_seq;
827 : : // ## endpoint->last_seq = last_seq;
828 : 53 : endpoint->InitStartSeq(base_seq);
829 : 53 : endpoint->InitAckSeq(base_seq);
830 : 53 : endpoint->InitLastSeq(last_seq);
831 : : }
832 : :
833 [ + + ][ + - ]: 15073 : if ( flags.FIN() && ! flags.RST() ) // ###
[ + + ]
834 : : { // should check sequence/ack numbers here ###
835 : 786 : endpoint->SetState(TCP_ENDPOINT_CLOSED);
836 : :
837 [ + + + + ]: 786 : if ( peer->state == TCP_ENDPOINT_RESET &&
838 : : peer->prev_state == TCP_ENDPOINT_CLOSED )
839 : : // The peer sent a FIN followed by a RST.
840 : : // Turn it back into CLOSED state, because
841 : : // this was actually normal termination.
842 : 4 : peer->SetState(TCP_ENDPOINT_CLOSED);
843 : :
844 : 786 : do_close = gen_event = 1;
845 : : }
846 : :
847 [ + + ]: 15073 : if ( flags.RST() )
848 : : {
849 : 26 : endpoint->SetState(TCP_ENDPOINT_RESET);
850 : 26 : do_close = 1;
851 : :
852 [ - + # # ]: 26 : if ( peer->state != TCP_ENDPOINT_RESET ||
853 : : peer->prev_state != TCP_ENDPOINT_ESTABLISHED )
854 : 26 : ConnectionReset();
855 : : }
856 : 15073 : }
857 : :
858 : : void TCP_Analyzer::UpdateClosedState(double t, TCP_Endpoint* endpoint,
859 : 760 : int delta_last, TCP_Flags flags, int& do_close)
860 : : {
861 [ - + ]: 760 : if ( flags.SYN() )
862 : 0 : Weird("SYN_after_close");
863 : :
864 [ + + ][ + + ]: 760 : if ( flags.FIN() && delta_last > 0 )
[ + + ]
865 : : // Probably should also complain on FIN recision.
866 : : // That requires an extra state variable to avoid
867 : : // generating slews of weird's when a TCP gets
868 : : // seriously confused (this from experience).
869 : 12 : Weird("FIN_advanced_last_seq");
870 : :
871 : : // Previously, our state was CLOSED, since we sent a FIN.
872 : : // If our peer was also closed, then don't change our state
873 : : // now on a RST, since this connection has already seen a FIN
874 : : // exchange.
875 [ + + ][ + + ]: 760 : if ( flags.RST() && endpoint->peer->state != TCP_ENDPOINT_CLOSED )
[ + + ]
876 : : {
877 : 37 : endpoint->SetState(TCP_ENDPOINT_RESET);
878 : :
879 [ + + ]: 37 : if ( ! endpoint->did_close )
880 : : // RST after FIN.
881 : 4 : do_close = 1;
882 : :
883 [ + - ]: 37 : if ( connection_reset )
884 : 37 : ADD_ANALYZER_TIMER(&TCP_Analyzer::ResetTimer,
885 : : t + tcp_reset_delay, 1,
886 : : TIMER_TCP_RESET);
887 : : }
888 : 760 : }
889 : :
890 : 15 : void TCP_Analyzer::UpdateResetState(int len, TCP_Flags flags)
891 : : {
892 [ - + ]: 15 : if ( flags.SYN() )
893 : 0 : Weird("SYN_after_reset");
894 [ - + ]: 15 : if ( flags.FIN() )
895 : 0 : Weird("FIN_after_reset");
896 : :
897 [ + + ][ - + ]: 15 : if ( len > 0 && ! flags.RST() )
[ - + ]
898 : 0 : Weird("data_after_reset");
899 : 15 : }
900 : :
901 : : void TCP_Analyzer::UpdateStateMachine(double t,
902 : : TCP_Endpoint* endpoint, TCP_Endpoint* peer,
903 : : uint32 base_seq, uint32 ack_seq, uint32 last_seq,
904 : : int len, int delta_last, int is_orig, TCP_Flags flags,
905 : 17976 : int& do_close, int& gen_event)
906 : : {
907 : 17976 : do_close = 0; // whether to report the connection as closed
908 : 17976 : gen_event = 0; // if so, whether to generate an event
909 : :
910 [ + + + + + : 17976 : switch ( endpoint->state ) {
- ]
911 : :
912 : : case TCP_ENDPOINT_INACTIVE:
913 : : UpdateInactiveState(t, endpoint, peer, base_seq, ack_seq,
914 : : len, is_orig, flags,
915 : 1732 : do_close, gen_event);
916 : 1732 : break;
917 : :
918 : : case TCP_ENDPOINT_SYN_SENT:
919 : : case TCP_ENDPOINT_SYN_ACK_SENT:
920 : : UpdateSYN_SentState(t, endpoint, peer, base_seq, last_seq,
921 : : len, is_orig, flags,
922 : 396 : do_close, gen_event);
923 : 396 : break;
924 : :
925 : : case TCP_ENDPOINT_ESTABLISHED:
926 : : case TCP_ENDPOINT_PARTIAL:
927 : : UpdateEstablishedState(t, endpoint, peer, base_seq, last_seq,
928 : 15073 : is_orig, flags, do_close, gen_event);
929 : 15073 : break;
930 : :
931 : : case TCP_ENDPOINT_CLOSED:
932 : 760 : UpdateClosedState(t, endpoint, delta_last, flags, do_close);
933 : 760 : break;
934 : :
935 : : case TCP_ENDPOINT_RESET:
936 : 15 : UpdateResetState(len, flags);
937 : : break;
938 : : }
939 : 17976 : }
940 : :
941 : : void TCP_Analyzer::GeneratePacketEvent(TCP_Endpoint* endpoint,
942 : : TCP_Endpoint* peer,
943 : : uint32 base_seq, uint32 ack_seq,
944 : : const u_char* data, int len, int caplen,
945 : 0 : int is_orig, TCP_Flags flags)
946 : : {
947 : : char tcp_flags[256];
948 : 0 : int tcp_flag_len = 0;
949 : :
950 [ # # ]: 0 : if ( flags.SYN() ) tcp_flags[tcp_flag_len++] = 'S';
951 [ # # ]: 0 : if ( flags.FIN() ) tcp_flags[tcp_flag_len++] = 'F';
952 [ # # ]: 0 : if ( flags.RST() ) tcp_flags[tcp_flag_len++] = 'R';
953 [ # # ]: 0 : if ( flags.ACK() ) tcp_flags[tcp_flag_len++] = 'A';
954 [ # # ]: 0 : if ( flags.PUSH() ) tcp_flags[tcp_flag_len++] = 'P';
955 [ # # ]: 0 : if ( flags.URG() ) tcp_flags[tcp_flag_len++] = 'U';
956 : :
957 : 0 : tcp_flags[tcp_flag_len] = '\0';
958 : :
959 : 0 : val_list* vl = new val_list();
960 : :
961 : 0 : vl->append(BuildConnVal());
962 : 0 : vl->append(new Val(is_orig, TYPE_BOOL));
963 : 0 : vl->append(new StringVal(tcp_flags));
964 : 0 : vl->append(new Val(base_seq - endpoint->StartSeq(), TYPE_COUNT));
965 : : vl->append(new Val(flags.ACK() ?
966 [ # # ]: 0 : ack_seq - peer->StartSeq() : 0, TYPE_COUNT));
967 : 0 : vl->append(new Val(len, TYPE_COUNT));
968 : :
969 : : // We need the min() here because Ethernet padding can lead to
970 : : // caplen > len.
971 : 0 : vl->append(new StringVal(min(caplen, len), (const char*) data));
972 : :
973 : 0 : ConnectionEvent(tcp_packet, vl);
974 : 0 : }
975 : :
976 : : int TCP_Analyzer::DeliverData(double t, const u_char* data, int len, int caplen,
977 : : const IP_Hdr* ip, const struct tcphdr* tp,
978 : : TCP_Endpoint* endpoint, uint32 base_seq,
979 : 9174 : int is_orig, TCP_Flags flags)
980 : : {
981 : 9174 : int data_seq = base_seq - endpoint->StartSeq();
982 [ - + ]: 9174 : if ( flags.SYN() )
983 : 0 : ++data_seq; // skip over SYN octet
984 : :
985 : : int need_contents = endpoint->DataSent(t, data_seq,
986 : 9174 : len, caplen, data, ip, tp);
987 : :
988 [ - + ]: 9174 : LOOP_OVER_GIVEN_CHILDREN(i, packet_children)
989 : 0 : (*i)->NextPacket(len, data, is_orig, data_seq, ip, caplen);
990 : :
991 : 9174 : return need_contents;
992 : : }
993 : :
994 : 17976 : void TCP_Analyzer::CheckRecording(int need_contents, TCP_Flags flags)
995 : : {
996 [ + + ][ + - ]: 17976 : bool record_current_content = need_contents || Conn()->RecordContents();
997 : : bool record_current_packet =
998 : : Conn()->RecordPackets() ||
999 [ - + ][ # # ]: 17976 : flags.SYN() || flags.FIN() || flags.RST();
[ # # ][ # # ]
1000 : :
1001 : 17976 : Conn()->SetRecordCurrentContent(record_current_content);
1002 : 17976 : Conn()->SetRecordCurrentPacket(record_current_packet);
1003 : 17976 : }
1004 : :
1005 : 17976 : void TCP_Analyzer::CheckPIA_FirstPacket(int is_orig, const IP_Hdr* ip)
1006 : : {
1007 [ + + ][ + + ]: 17976 : if ( is_orig && ! (first_packet_seen & ORIG) )
1008 : : {
1009 : 842 : PIA_TCP* pia = static_cast<PIA_TCP*>(Conn()->GetPrimaryPIA());
1010 [ + - ]: 842 : if ( pia )
1011 : 842 : pia->FirstPacket(is_orig, ip);
1012 : 842 : first_packet_seen |= ORIG;
1013 : : }
1014 : :
1015 [ + + ][ + + ]: 17976 : if ( ! is_orig && ! (first_packet_seen & RESP) )
1016 : : {
1017 : 880 : PIA_TCP* pia = static_cast<PIA_TCP*>(Conn()->GetPrimaryPIA());
1018 [ + - ]: 880 : if ( pia )
1019 : 880 : pia->FirstPacket(is_orig, ip);
1020 : 880 : first_packet_seen |= RESP;
1021 : : }
1022 : 17976 : }
1023 : :
1024 : : void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
1025 : 17976 : int seq, const IP_Hdr* ip, int caplen)
1026 : : {
1027 : 17976 : TransportLayerAnalyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
1028 : :
1029 : 17976 : const struct tcphdr* tp = ExtractTCP_Header(data, len, caplen);
1030 [ - + ]: 17976 : if ( ! tp )
1031 : 0 : return;
1032 : :
1033 : : // We need the min() here because Ethernet frame padding can lead to
1034 : : // caplen > len.
1035 [ - + ]: 17976 : if ( packet_contents )
1036 : 0 : PacketContents(data, min(len, caplen));
1037 : :
1038 [ + + ]: 17976 : TCP_Endpoint* endpoint = is_orig ? orig : resp;
1039 : 17976 : TCP_Endpoint* peer = endpoint->peer;
1040 : :
1041 [ - + ]: 17976 : if ( ! ValidateChecksum(tp, endpoint, len, caplen) )
1042 : 0 : return;
1043 : :
1044 : 17976 : TCP_Flags flags(tp);
1045 : :
1046 : 17976 : uint32 base_seq = ntohl(tp->th_seq);
1047 : 17976 : uint32 ack_seq = ntohl(tp->th_ack);
1048 : :
1049 : 17976 : CheckFlagCombos(flags, endpoint, base_seq, len, ntohs(tp->th_dport));
1050 : :
1051 : 17976 : UpdateWindow(endpoint, ntohs(tp->th_win), base_seq, ack_seq, flags);
1052 : :
1053 : 17976 : double t = current_timestamp;
1054 : :
1055 [ + + + + ]: 17976 : if ( ! orig->did_close || ! resp->did_close )
1056 : 17490 : Conn()->SetLastTime(t);
1057 : :
1058 : 17976 : const uint32* orig_addr = Conn()->OrigAddr();
1059 : 17976 : const uint32* resp_addr = Conn()->RespAddr();
1060 : :
1061 : 17976 : uint32 tcp_hdr_len = data - (const u_char*) tp;
1062 : :
1063 : 17976 : int seq_len = len; // length in terms of sequence space
1064 : :
1065 [ - + ]: 17976 : if ( ! ProcessFlags(t, ip, tp, tcp_hdr_len, len, seq_len,
1066 : : endpoint, peer, base_seq, ack_seq,
1067 : : orig_addr, is_orig, flags) )
1068 : 0 : return;
1069 : :
1070 : 17976 : uint32 last_seq = base_seq + seq_len;
1071 : :
1072 [ + + ]: 17976 : if ( endpoint->state == TCP_ENDPOINT_INACTIVE )
1073 : : TransitionFromInactive(t, endpoint, base_seq, last_seq,
1074 : 1732 : flags.SYN());
1075 : :
1076 : 17976 : int delta_last = UpdateLastSeq(endpoint, last_seq, flags);
1077 : :
1078 : 17976 : endpoint->last_time = t;
1079 : :
1080 : : int do_close;
1081 : : int gen_event;
1082 : : UpdateStateMachine(t, endpoint, peer, base_seq, ack_seq, last_seq,
1083 : : len, delta_last, is_orig, flags,
1084 : 17976 : do_close, gen_event);
1085 : :
1086 [ - + ]: 17976 : if ( tcp_packet )
1087 : : GeneratePacketEvent(endpoint, peer, base_seq, ack_seq,
1088 : 0 : data, len, caplen, is_orig, flags);
1089 : :
1090 [ - + ][ # # ]: 17976 : if ( tcp_option && tcp_hdr_len > sizeof(*tp) &&
[ # # ][ - + ]
1091 : : tcp_hdr_len <= uint32(caplen) )
1092 : 0 : ParseTCPOptions(tp, TCPOptionEvent, this, is_orig, 0);
1093 : :
1094 [ - + ][ # # ]: 17976 : if ( TraceRewriter() && current_hdr )
[ - + ]
1095 : : {
1096 : 0 : TCP_Rewriter* r = (TCP_Rewriter*) TraceRewriter();
1097 : : r->NextPacket(is_orig, t, current_hdr, current_pkt,
1098 : 0 : current_hdr_size, ip->IP4_Hdr(), tp);
1099 : : }
1100 : :
1101 [ - + ][ # # ]: 17976 : if ( src_pkt_writer && current_hdr )
1102 : 0 : src_pkt_writer->NextPacket(current_hdr, current_pkt);
1103 : :
1104 : : if ( DEBUG_tcp_data_sent )
1105 : : {
1106 : : DEBUG_MSG("%.6f before DataSent: len=%d caplen=%d skip=%d\n",
1107 : : network_time, len, caplen, Skipping());
1108 : : }
1109 : :
1110 : 17976 : int need_contents = 0;
1111 [ + + ][ - + ]: 17976 : if ( len > 0 && (caplen >= len || packet_children.size()) &&
[ # # ][ + + ]
[ + - ][ + + ]
1112 : : ! flags.RST() && ! Skipping() )
1113 : : need_contents = DeliverData(t, data, len, caplen, ip, tp,
1114 : : endpoint, base_seq,
1115 : 9174 : is_orig, flags);
1116 : :
1117 : 17976 : endpoint->CheckEOF();
1118 : :
1119 [ + + ]: 17976 : if ( do_close )
1120 : : {
1121 : : // We need to postpone doing this until after we process
1122 : : // DataSent, so we don't generate a connection_finished event
1123 : : // until after data perhaps included with the FIN is processed.
1124 : 1047 : ConnectionClosed(endpoint, peer, gen_event);
1125 : : }
1126 : :
1127 : 17976 : CheckRecording(need_contents, flags);
1128 : :
1129 [ - + ]: 17976 : if ( ! reassembling )
1130 : : ForwardPacket(len, data, is_orig,
1131 : 0 : base_seq - endpoint->StartSeq(), ip, caplen);
1132 : :
1133 : 17976 : CheckPIA_FirstPacket(is_orig, ip);
1134 : : }
1135 : :
1136 : 0 : void TCP_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
1137 : : {
1138 : 0 : Analyzer::DeliverStream(len, data, orig);
1139 : 0 : }
1140 : :
1141 : 0 : void TCP_Analyzer::Undelivered(int seq, int len, bool is_orig)
1142 : : {
1143 : 0 : Analyzer::Undelivered(seq, len, orig);
1144 : 0 : }
1145 : :
1146 : 0 : void TCP_Analyzer::FlipRoles()
1147 : : {
1148 : 0 : Analyzer::FlipRoles();
1149 : :
1150 : 0 : sessions->tcp_stats.FlipState(orig->state, resp->state);
1151 : 0 : TCP_Endpoint* tmp_ep = resp;
1152 : 0 : resp = orig;
1153 : 0 : orig = tmp_ep;
1154 : 0 : orig->is_orig = !orig->is_orig;
1155 : 0 : resp->is_orig = !resp->is_orig;
1156 : 0 : }
1157 : :
1158 : 31290 : void TCP_Analyzer::UpdateEndpointVal(RecordVal* endp, int is_orig)
1159 : : {
1160 [ + + ]: 31290 : TCP_Endpoint* s = is_orig ? orig : resp;
1161 : 31290 : endp->Assign(0, new Val(s->Size(), TYPE_COUNT));
1162 : 31290 : endp->Assign(1, new Val(int(s->state), TYPE_COUNT));
1163 : 31290 : }
1164 : :
1165 : : Val* TCP_Analyzer::BuildSYNPacketVal(int is_orig, const IP_Hdr* ip,
1166 : 1042 : const struct tcphdr* tcp)
1167 : : {
1168 : 1042 : int winscale = -1;
1169 : 1042 : int MSS = 0;
1170 : 1042 : int SACK = 0;
1171 : :
1172 : : // Parse TCP options.
1173 : 1042 : u_char* options = (u_char*) tcp + sizeof(struct tcphdr);
1174 : 1042 : u_char* opt_end = (u_char*) tcp + tcp->th_off * 4;
1175 : :
1176 [ + + ]: 4051 : while ( options < opt_end )
1177 : : {
1178 : 3080 : unsigned int opt = options[0];
1179 : :
1180 [ + + ]: 3080 : if ( opt == TCPOPT_EOL )
1181 : : // All done - could flag if more junk left over ....
1182 : 71 : break;
1183 : :
1184 [ + + ]: 3009 : if ( opt == TCPOPT_NOP )
1185 : : {
1186 : 1140 : ++options;
1187 : 1140 : continue;
1188 : : }
1189 : :
1190 [ - + ]: 1869 : if ( options + 1 >= opt_end )
1191 : : // We've run off the end, no room for the length.
1192 : 0 : break;
1193 : :
1194 : 1869 : unsigned int opt_len = options[1];
1195 : :
1196 [ - + ]: 1869 : if ( options + opt_len > opt_end )
1197 : : // No room for rest of option.
1198 : 0 : break;
1199 : :
1200 [ - + ]: 1869 : if ( opt_len == 0 )
1201 : : // Trashed length field.
1202 : 0 : break;
1203 : :
1204 [ + + + + ]: 1869 : switch ( opt ) {
1205 : : case TCPOPT_SACK_PERMITTED:
1206 : 480 : SACK = 1;
1207 : 480 : break;
1208 : :
1209 : : case TCPOPT_MAXSEG:
1210 [ - + ]: 518 : if ( opt_len < 4 )
1211 : 0 : break; // bad length
1212 : :
1213 : 518 : MSS = (options[2] << 8) | options[3];
1214 : 518 : break;
1215 : :
1216 : : case 3: // TCPOPT_WSCALE
1217 [ - + ]: 492 : if ( opt_len < 3 )
1218 : 0 : break; // bad length
1219 : :
1220 : 492 : winscale = options[2];
1221 : : break;
1222 : :
1223 : : default: // just skip over
1224 : : break;
1225 : : }
1226 : :
1227 : 1869 : options += opt_len;
1228 : : }
1229 : :
1230 : 1042 : RecordVal* v = new RecordVal(SYN_packet);
1231 : :
1232 : 1042 : v->Assign(0, new Val(is_orig, TYPE_BOOL));
1233 : 1042 : v->Assign(1, new Val(int(ip->DF()), TYPE_BOOL));
1234 : 1042 : v->Assign(2, new Val(int(ip->TTL()), TYPE_INT));
1235 : 1042 : v->Assign(3, new Val((ip->TotalLen()), TYPE_INT));
1236 : 1042 : v->Assign(4, new Val(ntohs(tcp->th_win), TYPE_INT));
1237 : 1042 : v->Assign(5, new Val(winscale, TYPE_INT));
1238 : 1042 : v->Assign(6, new Val(MSS, TYPE_INT));
1239 : 1042 : v->Assign(7, new Val(SACK, TYPE_BOOL));
1240 : :
1241 : 1042 : return v;
1242 : : }
1243 : :
1244 : : RecordVal* TCP_Analyzer::BuildOSVal(int is_orig, const IP_Hdr* ip,
1245 : 0 : const struct tcphdr* tcp, uint32 tcp_hdr_len)
1246 : : {
1247 [ # # ]: 0 : if ( ! is_orig )
1248 : : // Later we might use SYN-ACK fingerprinting here.
1249 : 0 : return 0;
1250 : :
1251 : : // Passive OS fingerprinting wants to know a lot about IP and TCP
1252 : : // options: how many options there are, and in which order.
1253 : 0 : int winscale = 0;
1254 : 0 : int MSS = 0;
1255 : 0 : int optcount = 0;
1256 : 0 : uint32 quirks = 0;
1257 : 0 : uint32 tstamp = 0;
1258 : : uint8 op[MAXOPT];
1259 : :
1260 [ # # ]: 0 : if ( ip->HdrLen() > 20 )
1261 : 0 : quirks |= QUIRK_IPOPT;
1262 : :
1263 [ # # ]: 0 : if ( ip->IP_ID() == 0 )
1264 : 0 : quirks |= QUIRK_ZEROID;
1265 : :
1266 [ # # ]: 0 : if ( tcp->th_seq == 0 )
1267 : 0 : quirks |= QUIRK_SEQ0;
1268 : :
1269 [ # # ]: 0 : if ( tcp->th_seq == tcp->th_ack )
1270 : 0 : quirks |= QUIRK_SEQEQ;
1271 : :
1272 [ # # ]: 0 : if ( tcp->th_flags & ~(TH_SYN|TH_ACK|TH_RST|TH_ECE|TH_CWR) )
1273 : 0 : quirks |= QUIRK_FLAGS;
1274 : :
1275 [ # # ]: 0 : if ( ip->TotalLen() - ip->HdrLen() - tcp_hdr_len > 0 )
1276 : 0 : quirks |= QUIRK_DATA; // SYN with data
1277 : :
1278 [ # # ]: 0 : if ( tcp->th_ack )
1279 : 0 : quirks |= QUIRK_ACK;
1280 [ # # ]: 0 : if ( tcp->th_urp )
1281 : 0 : quirks |= QUIRK_URG;
1282 [ # # ]: 0 : if ( tcp->th_x2 )
1283 : 0 : quirks |= QUIRK_X2;
1284 : :
1285 : : // Parse TCP options.
1286 : 0 : u_char* options = (u_char*) tcp + sizeof(struct tcphdr);
1287 : 0 : u_char* opt_end = (u_char*) tcp + tcp_hdr_len;
1288 : :
1289 [ # # ]: 0 : while ( options < opt_end )
1290 : : {
1291 : 0 : unsigned int opt = options[0];
1292 : :
1293 [ # # ]: 0 : if ( opt == TCPOPT_EOL )
1294 : : {
1295 : 0 : op[optcount++] = TCPOPT_EOL;
1296 [ # # ]: 0 : if ( ++options < opt_end )
1297 : 0 : quirks |= QUIRK_PAST;
1298 : :
1299 : : // All done - could flag if more junk left over ....
1300 : 0 : break;
1301 : : }
1302 : :
1303 [ # # ]: 0 : if ( opt == TCPOPT_NOP )
1304 : : {
1305 : 0 : op[optcount++] = TCPOPT_NOP;
1306 : 0 : ++options;
1307 : 0 : continue;
1308 : : }
1309 : :
1310 [ # # ]: 0 : if ( options + 1 >= opt_end )
1311 : : {
1312 : : // We've run off the end, no room for the length.
1313 : 0 : quirks |= QUIRK_BROKEN;
1314 : 0 : break;
1315 : : }
1316 : :
1317 : 0 : unsigned int opt_len = options[1];
1318 : :
1319 [ # # ]: 0 : if ( options + opt_len > opt_end )
1320 : : {
1321 : : // No room for rest of the options.
1322 : 0 : quirks |= QUIRK_BROKEN;
1323 : 0 : break;
1324 : : }
1325 : :
1326 [ # # ]: 0 : if ( opt_len == 0 )
1327 : : // Trashed length field.
1328 : 0 : break;
1329 : :
1330 [ # # # # : 0 : switch ( opt ) {
# ]
1331 : : case TCPOPT_SACK_PERMITTED:
1332 : : // SACKOK LEN
1333 : 0 : op[optcount] = TCPOPT_SACK_PERMITTED;
1334 : 0 : break;
1335 : :
1336 : : case TCPOPT_MAXSEG:
1337 : : // MSS LEN D0 D1
1338 [ # # ]: 0 : if ( opt_len < 4 )
1339 : 0 : break; // bad length
1340 : :
1341 : 0 : op[optcount] = TCPOPT_MAXSEG;
1342 : 0 : MSS = (options[2] << 8) | options[3];
1343 : 0 : break;
1344 : :
1345 : : case TCPOPT_WINDOW:
1346 : : // WSCALE LEN D0
1347 [ # # ]: 0 : if ( opt_len < 3 )
1348 : 0 : break; // bad length
1349 : :
1350 : 0 : op[optcount] = TCPOPT_WINDOW;
1351 : 0 : winscale = options[2];
1352 : 0 : break;
1353 : :
1354 : : case TCPOPT_TIMESTAMP:
1355 : : // TSTAMP LEN T0 T1 T2 T3 A0 A1 A2 A3
1356 [ # # ]: 0 : if ( opt_len < 10 )
1357 : 0 : break; // bad length
1358 : :
1359 : 0 : op[optcount] = TCPOPT_TIMESTAMP;
1360 : :
1361 : 0 : tstamp = ntohl(extract_uint32(options + 2));
1362 : :
1363 [ # # ]: 0 : if ( extract_uint32(options + 6) )
1364 : 0 : quirks |= QUIRK_T2;
1365 : 0 : break;
1366 : :
1367 : : default: // just skip over
1368 : 0 : op[optcount]=opt;
1369 : : break;
1370 : : }
1371 : :
1372 [ # # ]: 0 : if ( optcount < MAXOPT - 1 )
1373 : 0 : ++optcount;
1374 : : else
1375 : 0 : quirks |= QUIRK_BROKEN;
1376 : :
1377 : 0 : options += opt_len;
1378 : : }
1379 : :
1380 : : struct os_type os_from_print;
1381 : : int id = sessions->Get_OS_From_SYN(&os_from_print,
1382 : : uint16(ip->TotalLen()),
1383 : : uint8(ip->DF()), uint8(ip->TTL()),
1384 : : uint16(ntohs(tcp->th_win)),
1385 : : uint8(optcount), op,
1386 : : uint16(MSS), uint8(winscale),
1387 : : tstamp, quirks,
1388 : 0 : uint8(tcp->th_flags & (TH_ECE|TH_CWR)));
1389 : :
1390 [ # # ]: 0 : if ( sessions->CompareWithPreviousOSMatch(ip->SrcAddr4(), id) )
1391 : : {
1392 : 0 : RecordVal* os = new RecordVal(OS_version);
1393 : :
1394 : 0 : os->Assign(0, new StringVal(os_from_print.os));
1395 : :
1396 [ # # ]: 0 : if ( os_from_print.desc )
1397 : 0 : os->Assign(1, new StringVal(os_from_print.desc));
1398 : : else
1399 : 0 : os->Assign(1, new StringVal(""));
1400 : :
1401 : 0 : os->Assign(2, new Val(os_from_print.dist, TYPE_COUNT));
1402 : 0 : os->Assign(3, new EnumVal(os_from_print.match, OS_version_inference));
1403 : :
1404 : 0 : return os;
1405 : : }
1406 : :
1407 : 0 : return 0;
1408 : : }
1409 : :
1410 : : int TCP_Analyzer::ParseTCPOptions(const struct tcphdr* tcp,
1411 : : proc_tcp_option_t proc,
1412 : : TCP_Analyzer* analyzer,
1413 : 1104 : bool is_orig, void* cookie)
1414 : : {
1415 : : // Parse TCP options.
1416 : 1104 : const u_char* options = (const u_char*) tcp + sizeof(struct tcphdr);
1417 : 1104 : const u_char* opt_end = (const u_char*) tcp + tcp->th_off * 4;
1418 : :
1419 [ + + ]: 6577 : while ( options < opt_end )
1420 : : {
1421 : 5910 : unsigned int opt = options[0];
1422 : :
1423 : : unsigned int opt_len;
1424 : :
1425 [ + + ]: 5910 : if ( opt < 2 )
1426 : 2979 : opt_len = 1;
1427 : :
1428 [ - + ]: 2931 : else if ( options + 1 >= opt_end )
1429 : : // We've run off the end, no room for the length.
1430 : 0 : return -1;
1431 : :
1432 : : else
1433 : 2931 : opt_len = options[1];
1434 : :
1435 [ - + ]: 5910 : if ( opt_len == 0 )
1436 : 0 : return -1; // trashed length field
1437 : :
1438 [ - + ]: 5910 : if ( options + opt_len > opt_end )
1439 : : // No room for rest of option.
1440 : 0 : return -1;
1441 : :
1442 [ - + ]: 5910 : if ( (*proc)(opt, opt_len, options, analyzer, is_orig, cookie) == -1 )
1443 : 0 : return -1;
1444 : :
1445 : 5910 : options += opt_len;
1446 : :
1447 [ + + ]: 5910 : if ( opt == TCPOPT_EOL )
1448 : : // All done - could flag if more junk left over ....
1449 : 437 : break;
1450 : : }
1451 : :
1452 : 1104 : return 0;
1453 : : }
1454 : :
1455 : : int TCP_Analyzer::TCPOptionEvent(unsigned int opt,
1456 : : unsigned int optlen,
1457 : : const u_char* /* option */,
1458 : : TCP_Analyzer* analyzer,
1459 : 0 : bool is_orig, void* cookie)
1460 : : {
1461 [ # # ]: 0 : if ( tcp_option )
1462 : : {
1463 : 0 : val_list* vl = new val_list();
1464 : :
1465 : 0 : vl->append(analyzer->BuildConnVal());
1466 : 0 : vl->append(new Val(is_orig, TYPE_BOOL));
1467 : 0 : vl->append(new Val(opt, TYPE_COUNT));
1468 : 0 : vl->append(new Val(optlen, TYPE_COUNT));
1469 : :
1470 : 0 : analyzer->ConnectionEvent(tcp_option, vl);
1471 : : }
1472 : :
1473 : 0 : return 0;
1474 : : }
1475 : :
1476 : 295 : void TCP_Analyzer::AttemptTimer(double /* t */)
1477 : : {
1478 [ - + ]: 295 : if ( ! is_active )
1479 : 0 : return;
1480 : :
1481 [ + + ][ + + ]: 295 : if ( (orig->state == TCP_ENDPOINT_SYN_SENT ||
[ + + ]
1482 : : orig->state == TCP_ENDPOINT_SYN_ACK_SENT) &&
1483 : : resp->state == TCP_ENDPOINT_INACTIVE )
1484 : : {
1485 : 4 : Event(connection_attempt);
1486 : 4 : is_active = 0;
1487 : :
1488 : : // All done with this connection.
1489 : 295 : sessions->Remove(Conn());
1490 : : }
1491 : : }
1492 : :
1493 : 4 : void TCP_Analyzer::PartialCloseTimer(double /* t */)
1494 : : {
1495 [ - + ]: 4 : if ( ! is_active )
1496 : 0 : return;
1497 : :
1498 [ + - ][ + - ]: 4 : if ( orig->state != TCP_ENDPOINT_INACTIVE &&
[ - + ][ # # ]
1499 : : resp->state != TCP_ENDPOINT_INACTIVE &&
1500 : : (! orig->did_close || ! resp->did_close) )
1501 : : {
1502 [ + - ][ - + ]: 4 : if ( orig->state == TCP_ENDPOINT_RESET ||
1503 : : resp->state == TCP_ENDPOINT_RESET )
1504 : : // Presumably the RST is what caused the partial
1505 : : // close. Don't report it.
1506 : 0 : return;
1507 : :
1508 : 4 : Event(connection_partial_close);
1509 : 4 : sessions->Remove(Conn());
1510 : : }
1511 : : }
1512 : :
1513 : 15596 : void TCP_Analyzer::ExpireTimer(double t)
1514 : : {
1515 [ + + ]: 15596 : if ( ! is_active )
1516 : 8 : return;
1517 : :
1518 [ + + ]: 15588 : if ( Conn()->LastTime() + tcp_connection_linger < t )
1519 : : {
1520 [ + + ][ + + ]: 15022 : if ( orig->did_close || resp->did_close )
1521 : : {
1522 : : // No activity for tcp_connection_linger seconds, and
1523 : : // at least one side has closed. See whether
1524 : : // connection has likely terminated.
1525 [ + + ][ + - ]: 6763 : if ( (orig->did_close && resp->did_close) ||
[ + - ][ + + ]
[ + - ][ - + ]
1526 : : (orig->state == TCP_ENDPOINT_RESET ||
1527 : : resp->state == TCP_ENDPOINT_RESET) ||
1528 : : (orig->state == TCP_ENDPOINT_INACTIVE ||
1529 : : resp->state == TCP_ENDPOINT_INACTIVE) )
1530 : : {
1531 : : // Either both closed, or one RST,
1532 : : // or half-closed.
1533 : :
1534 : : // The Timer has Ref()'d us and won't Unref()
1535 : : // us until we return, so it's safe to have
1536 : : // the session remove and Unref() us here.
1537 : 2 : Event(connection_timeout);
1538 : 2 : is_active = 0;
1539 : 2 : sessions->Remove(Conn());
1540 : 2 : return;
1541 : : }
1542 : : }
1543 : :
1544 [ + + ]: 15020 : if ( resp->state == TCP_ENDPOINT_INACTIVE )
1545 : : {
1546 [ + + ][ - + ]: 474 : if ( (orig->state == TCP_ENDPOINT_SYN_SENT ||
1547 : : orig->state == TCP_ENDPOINT_SYN_ACK_SENT) )
1548 : : {
1549 [ - + ]: 3 : if ( ! connection_attempt )
1550 : : {
1551 : : // Time out the connection attempt,
1552 : : // since the AttemptTimer isn't going
1553 : : // to do it for us, and we don't want
1554 : : // to clog the data structures with
1555 : : // old, failed attempts.
1556 : 0 : Event(connection_timeout);
1557 : 0 : is_active = 0;
1558 : 0 : sessions->Remove(Conn());
1559 : 0 : return;
1560 : : }
1561 : : }
1562 : :
1563 [ - + ]: 468 : else if ( orig->state == TCP_ENDPOINT_INACTIVE )
1564 : : {
1565 : : // Nothing ever happened on this connection.
1566 : : // This can occur when we see a trashed
1567 : : // packet - it's discarded by NextPacket
1568 : : // before setting up an attempt timer,
1569 : : // so we need to clean it up here.
1570 : 0 : Event(connection_timeout);
1571 : 0 : sessions->Remove(Conn());
1572 : 0 : return;
1573 : : }
1574 : : }
1575 : : }
1576 : :
1577 : : // Connection still active, so reschedule timer.
1578 : : // ### if PQ_Element's were BroObj's, could just Ref the timer
1579 : : // and adjust its value here, instead of creating a new timer.
1580 : 15596 : ADD_ANALYZER_TIMER(&TCP_Analyzer::ExpireTimer, t + tcp_session_timer,
1581 : : 0, TIMER_TCP_EXPIRE);
1582 : : }
1583 : :
1584 : 24 : void TCP_Analyzer::ResetTimer(double /* t */)
1585 : : {
1586 [ - + ]: 24 : if ( ! is_active )
1587 : 0 : return;
1588 : :
1589 [ + - ]: 24 : if ( ! BothClosed() )
1590 : 24 : ConnectionReset();
1591 : :
1592 : 24 : sessions->Remove(Conn());
1593 : : }
1594 : :
1595 : 0 : void TCP_Analyzer::DeleteTimer(double /* t */)
1596 : : {
1597 : 0 : sessions->Remove(Conn());
1598 : 0 : }
1599 : :
1600 : :
1601 : : // The following need to be consistent with bro.init.
1602 : : #define CONTENTS_NONE 0
1603 : : #define CONTENTS_ORIG 1
1604 : : #define CONTENTS_RESP 2
1605 : : #define CONTENTS_BOTH 3
1606 : :
1607 : 0 : void TCP_Analyzer::SetContentsFile(unsigned int direction, BroFile* f)
1608 : : {
1609 [ # # ]: 0 : if ( direction == CONTENTS_NONE )
1610 : : {
1611 : 0 : orig->SetContentsFile(0);
1612 : 0 : resp->SetContentsFile(0);
1613 : : }
1614 : :
1615 : : else
1616 : : {
1617 [ # # ][ # # ]: 0 : if ( direction == CONTENTS_ORIG || direction == CONTENTS_BOTH )
1618 : 0 : orig->SetContentsFile(f);
1619 [ # # ][ # # ]: 0 : if ( direction == CONTENTS_RESP || direction == CONTENTS_BOTH )
1620 : 0 : resp->SetContentsFile(f);
1621 : : }
1622 : 0 : }
1623 : :
1624 : 0 : BroFile* TCP_Analyzer::GetContentsFile(unsigned int direction) const
1625 : : {
1626 [ # # # # : 0 : switch ( direction ) {
# ]
1627 : : case CONTENTS_NONE:
1628 : 0 : return 0;
1629 : :
1630 : : case CONTENTS_ORIG:
1631 : 0 : return orig->GetContentsFile();
1632 : :
1633 : : case CONTENTS_RESP:
1634 : 0 : return resp->GetContentsFile();
1635 : :
1636 : : case CONTENTS_BOTH:
1637 [ # # ]: 0 : if ( orig->GetContentsFile() != resp->GetContentsFile())
1638 : : // This is an "error".
1639 : 0 : return 0;
1640 : : else
1641 : 0 : return orig->GetContentsFile();
1642 : :
1643 : : default:
1644 : : break;
1645 : : }
1646 : 0 : internal_error("inconsistency in TCP_Analyzer::GetContentsFile");
1647 : : return 0;
1648 : : }
1649 : :
1650 : : void TCP_Analyzer::ConnectionClosed(TCP_Endpoint* endpoint, TCP_Endpoint* peer,
1651 : 1093 : int gen_event)
1652 : : {
1653 : 1093 : const analyzer_list& children(GetChildren());
1654 [ + + ]: 2929 : LOOP_OVER_CONST_CHILDREN(i)
1655 : : // Using this type of cast here is nasty (will crash if
1656 : : // we inadvertantly have a child analyzer that's not a
1657 : : // TCP_ApplicationAnalyzer), but we have to ...
1658 : : static_cast<TCP_ApplicationAnalyzer*>
1659 : 1836 : (*i)->ConnectionClosed(endpoint, peer, gen_event);
1660 : :
1661 [ + + ]: 1093 : if ( DataPending(endpoint) )
1662 : : {
1663 : : // Don't close out the connection yet, there's still data to
1664 : : // deliver.
1665 : 77 : close_deferred = 1;
1666 [ + + ]: 77 : if ( ! deferred_gen_event )
1667 : 69 : deferred_gen_event = gen_event;
1668 : 77 : return;
1669 : : }
1670 : :
1671 : 1016 : close_deferred = 0;
1672 : :
1673 [ + + ]: 1016 : if ( endpoint->did_close )
1674 : 13 : return; // nothing new to report
1675 : :
1676 : 1003 : endpoint->did_close = 1;
1677 : :
1678 : : int close_complete =
1679 : : endpoint->state == TCP_ENDPOINT_RESET ||
1680 : : peer->did_close ||
1681 [ + + ][ + + ]: 1003 : peer->state == TCP_ENDPOINT_INACTIVE;
[ + + ]
1682 : :
1683 : : if ( DEBUG_tcp_connection_close )
1684 : : {
1685 : : DEBUG_MSG("%.6f close_complete=%d tcp_close_delay=%f\n",
1686 : : network_time, close_complete, tcp_close_delay);
1687 : : }
1688 : :
1689 [ + + ]: 1003 : if ( close_complete )
1690 : : {
1691 [ + + ][ + + ]: 570 : if ( endpoint->prev_state != TCP_ENDPOINT_INACTIVE ||
1692 : : peer->state != TCP_ENDPOINT_INACTIVE )
1693 : : {
1694 [ + + ]: 418 : if ( deferred_gen_event )
1695 : : {
1696 : 22 : gen_event = 1;
1697 : 22 : deferred_gen_event = 0; // clear flag
1698 : : }
1699 : :
1700 : : // We have something interesting to report.
1701 [ + + ]: 418 : if ( gen_event )
1702 : : {
1703 [ + + ]: 395 : if ( peer->state == TCP_ENDPOINT_INACTIVE )
1704 : 26 : ConnectionFinished(1);
1705 : : else
1706 : 369 : ConnectionFinished(0);
1707 : : }
1708 : : }
1709 : :
1710 : 570 : CancelTimers();
1711 : :
1712 : : // Note, even if tcp_close_delay is zero, we can't
1713 : : // simply do:
1714 : : //
1715 : : // sessions->Remove(this);
1716 : : //
1717 : : // here, because that would cause the object to be
1718 : : // deleted out from under us.
1719 [ + - ]: 570 : if ( tcp_close_delay != 0.0 )
1720 : 570 : ADD_ANALYZER_TIMER(&TCP_Analyzer::ConnDeleteTimer,
1721 : : Conn()->LastTime() + tcp_close_delay, 0,
1722 : : TIMER_CONN_DELETE);
1723 : : else
1724 : 570 : ADD_ANALYZER_TIMER(&TCP_Analyzer::DeleteTimer, Conn()->LastTime(), 0,
1725 : : TIMER_TCP_DELETE);
1726 : : }
1727 : :
1728 : : else
1729 : : { // We haven't yet seen a full close.
1730 [ + + ]: 433 : if ( endpoint->prev_state == TCP_ENDPOINT_INACTIVE )
1731 : : { // First time we've seen anything from this side.
1732 [ + - ]: 8 : if ( connection_partial_close )
1733 : 8 : ADD_ANALYZER_TIMER(&TCP_Analyzer::PartialCloseTimer,
1734 : : Conn()->LastTime() + tcp_partial_close_delay, 0,
1735 : : TIMER_TCP_PARTIAL_CLOSE );
1736 : : }
1737 : :
1738 : : else
1739 : : {
1740 : : // Create a timer to look for the other side closing,
1741 : : // too.
1742 : 1093 : ADD_ANALYZER_TIMER(&TCP_Analyzer::ExpireTimer,
1743 : : Conn()->LastTime() + tcp_session_timer, 0,
1744 : : TIMER_TCP_EXPIRE);
1745 : : }
1746 : : }
1747 : : }
1748 : :
1749 : 395 : void TCP_Analyzer::ConnectionFinished(int half_finished)
1750 : : {
1751 : 395 : const analyzer_list& children(GetChildren());
1752 [ + + ]: 1062 : LOOP_OVER_CONST_CHILDREN(i)
1753 : : // Again, nasty - see TCP_Analyzer::ConnectionClosed.
1754 : : static_cast<TCP_ApplicationAnalyzer*>
1755 : 667 : (*i)->ConnectionFinished(half_finished);
1756 : :
1757 [ + + ]: 395 : if ( half_finished )
1758 : 26 : Event(connection_half_finished);
1759 : : else
1760 : 369 : Event(connection_finished);
1761 : :
1762 : 395 : is_active = 0;
1763 : 395 : }
1764 : :
1765 : 50 : void TCP_Analyzer::ConnectionReset()
1766 : : {
1767 : 50 : Event(connection_reset);
1768 : :
1769 : 50 : const analyzer_list& children(GetChildren());
1770 [ + + ]: 141 : LOOP_OVER_CONST_CHILDREN(i)
1771 : 91 : static_cast<TCP_ApplicationAnalyzer*>(*i)->ConnectionReset();
1772 : :
1773 : 50 : is_active = 0;
1774 : 50 : }
1775 : :
1776 : 0 : bool TCP_Analyzer::HadGap(bool is_orig) const
1777 : : {
1778 [ # # ]: 0 : TCP_Endpoint* endp = is_orig ? orig : resp;
1779 [ # # ][ # # ]: 0 : return endp && endp->HadGap();
1780 : : }
1781 : :
1782 : 1139 : int TCP_Analyzer::DataPending(TCP_Endpoint* closing_endp)
1783 : : {
1784 [ - + ]: 1139 : if ( Skipping() )
1785 : 0 : return 0;
1786 : :
1787 : 1139 : return closing_endp->DataPending();
1788 : : }
1789 : :
1790 : 1010 : void TCP_Analyzer::EndpointEOF(TCP_Reassembler* endp)
1791 : : {
1792 [ - + ]: 1010 : if ( connection_EOF )
1793 : : {
1794 : 0 : val_list* vl = new val_list();
1795 : 0 : vl->append(BuildConnVal());
1796 : 0 : vl->append(new Val(endp->IsOrig(), TYPE_BOOL));
1797 : 0 : ConnectionEvent(connection_EOF, vl);
1798 : : }
1799 : :
1800 : 1010 : const analyzer_list& children(GetChildren());
1801 [ + + ]: 2737 : LOOP_OVER_CONST_CHILDREN(i)
1802 : 1727 : static_cast<TCP_ApplicationAnalyzer*>(*i)->EndpointEOF(endp->IsOrig());
1803 : :
1804 : 1010 : TraceRewriterEOF(endp);
1805 : :
1806 [ + + ]: 1010 : if ( close_deferred )
1807 : : {
1808 [ - + ]: 46 : if ( DataPending(endp->Endpoint()) )
1809 : : {
1810 [ # # ]: 0 : if ( BothClosed() )
1811 : 0 : Weird("pending_data_when_closed");
1812 : :
1813 : : // Defer further, until the other endpoint
1814 : : // EOF's, too.
1815 : : }
1816 : :
1817 : : ConnectionClosed(endp->Endpoint(), endp->Endpoint()->peer,
1818 : 46 : deferred_gen_event);
1819 : 46 : close_deferred = 0;
1820 : : }
1821 : 1010 : }
1822 : :
1823 : 1010 : void TCP_Analyzer::TraceRewriterEOF(TCP_Reassembler* endp)
1824 : : {
1825 : 1010 : const analyzer_list& children(GetChildren());
1826 [ + + ]: 2737 : LOOP_OVER_CONST_CHILDREN(i)
1827 : 1727 : static_cast<TCP_ApplicationAnalyzer*>(*i)->TraceRewriterEOF(endp->IsOrig());
1828 : :
1829 : 1010 : TCP_Rewriter* r = (TCP_Rewriter*) TraceRewriter();
1830 [ - + ]: 1010 : if ( r )
1831 : : {
1832 : : // Add a FIN packet if there is one in the original trace.
1833 : : int FIN_cnt = endp->IsOrig() ?
1834 : : endp->GetTCPAnalyzer()->Orig()->FIN_cnt :
1835 [ # # ]: 0 : endp->GetTCPAnalyzer()->Resp()->FIN_cnt;
1836 : :
1837 [ # # ]: 0 : if ( FIN_cnt > 0 )
1838 : 0 : r->ScheduleFIN(endp->IsOrig());
1839 : : }
1840 : 1010 : }
1841 : :
1842 : 181 : void TCP_Analyzer::PacketWithRST()
1843 : : {
1844 : 181 : const analyzer_list& children(GetChildren());
1845 [ + + ]: 493 : LOOP_OVER_CONST_CHILDREN(i)
1846 : 312 : static_cast<TCP_ApplicationAnalyzer *>(*i)->PacketWithRST();
1847 : 181 : }
1848 : :
1849 : 16528 : bool TCP_Analyzer::IsReuse(double t, const u_char* pkt)
1850 : : {
1851 : 16528 : const struct tcphdr* tp = (const struct tcphdr*) pkt;
1852 : :
1853 [ - + ]: 16528 : if ( unsigned(tp->th_off) < sizeof(struct tcphdr) / 4 )
1854 : : // Bogus header, don't interpret further.
1855 : 0 : return false;
1856 : :
1857 : 16528 : TCP_Endpoint* conn_orig = orig;
1858 : :
1859 : : // Reuse only occurs on initial SYN's, except for half connections
1860 : : // it can occur on SYN-acks.
1861 [ + + ]: 16528 : if ( ! (tp->th_flags & TH_SYN) )
1862 : 16457 : return false;
1863 : :
1864 [ + + ]: 71 : if ( (tp->th_flags & TH_ACK) )
1865 : : {
1866 [ + - ]: 46 : if ( orig->state != TCP_ENDPOINT_INACTIVE )
1867 : : // Not a half connection.
1868 : 46 : return false;
1869 : :
1870 : 0 : conn_orig = resp;
1871 : : }
1872 : :
1873 [ + + ]: 25 : if ( ! IsClosed() )
1874 : : {
1875 : 22 : uint32 base_seq = ntohl(tp->th_seq);
1876 [ + + ]: 22 : if ( base_seq == conn_orig->StartSeq() )
1877 : 11 : return false;
1878 : :
1879 [ + - ][ - + ]: 11 : if ( (tp->th_flags & TH_ACK) == 0 &&
[ # # ][ # # ]
[ - + ]
1880 : : conn_orig->state == TCP_ENDPOINT_SYN_ACK_SENT &&
1881 : : resp->state == TCP_ENDPOINT_INACTIVE &&
1882 : : base_seq == resp->StartSeq() )
1883 : : {
1884 : : // This is an initial SYN with the right sequence
1885 : : // number, and the state is consistent with the
1886 : : // SYN & the SYN-ACK being flipped (e.g., due to
1887 : : // reading from two interfaces w/ interrupt
1888 : : // coalescence). Don't treat this as a reuse.
1889 : : // NextPacket() will flip set the connection
1890 : : // state correctly
1891 : 0 : return false;
1892 : : }
1893 : :
1894 [ + + ]: 11 : if ( conn_orig->state == TCP_ENDPOINT_SYN_SENT )
1895 : 7 : Weird("SYN_seq_jump");
1896 : : else
1897 : 11 : Weird("active_connection_reuse");
1898 : : }
1899 : :
1900 [ + + ][ - + ]: 3 : else if ( (orig->IsActive() || resp->IsActive()) &&
[ + - ][ - + ]
[ - + ]
1901 : : orig->state != TCP_ENDPOINT_RESET &&
1902 : : resp->state != TCP_ENDPOINT_RESET )
1903 : 0 : Weird("active_connection_reuse");
1904 : :
1905 [ + - ][ + + ]: 3 : else if ( t - Conn()->LastTime() < tcp_connection_linger &&
[ - + ][ - + ]
1906 : : orig->state != TCP_ENDPOINT_RESET &&
1907 : : resp->state != TCP_ENDPOINT_RESET )
1908 : 0 : Weird("premature_connection_reuse");
1909 : :
1910 : 16528 : return true;
1911 : : }
1912 : :
1913 : 1631 : void TCP_ApplicationAnalyzer::Init()
1914 : : {
1915 : 1631 : Analyzer::Init();
1916 : :
1917 [ + - ]: 1631 : if ( Parent()->GetTag() == AnalyzerTag::TCP )
1918 : 1631 : SetTCP(static_cast<TCP_Analyzer*>(Parent()));
1919 : 1631 : }
1920 : :
1921 : : void TCP_ApplicationAnalyzer::ProtocolViolation(const char* reason,
1922 : 0 : const char* data, int len)
1923 : : {
1924 : 0 : TCP_Analyzer* tcp = TCP();
1925 : :
1926 [ # # # # ]: 0 : if ( tcp &&
[ # # ][ # # ]
[ # # ]
1927 : : (tcp->IsPartial() || tcp->HadGap(false) || tcp->HadGap(true)) )
1928 : : // Filter out incomplete connections. Parsing them is
1929 : : // too unreliable.
1930 : 0 : return;
1931 : :
1932 : 0 : Analyzer::ProtocolViolation(reason, data, len);
1933 : : }
1934 : :
1935 : : void TCP_ApplicationAnalyzer::DeliverPacket(int len, const u_char* data,
1936 : : bool is_orig, int seq,
1937 : 0 : const IP_Hdr* ip, int caplen)
1938 : : {
1939 : 0 : Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);
1940 [ # # ][ # # ]: 0 : DBG_LOG(DBG_DPD, "TCP_ApplicationAnalyzer ignoring DeliverPacket(%d, %s, %d, %p, %d) [%s%s]",
1941 : : len, is_orig ? "T" : "F", seq, ip, caplen,
1942 : : fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
1943 : 0 : }
1944 : :
1945 : 0 : void TCP_ApplicationAnalyzer::SetEnv(bool /* is_orig */, char* name, char* val)
1946 : : {
1947 [ # # ]: 0 : delete [] name;
1948 [ # # ]: 0 : delete [] val;
1949 : 0 : }
1950 : :
1951 : 1727 : void TCP_ApplicationAnalyzer::EndpointEOF(bool is_orig)
1952 : : {
1953 [ + + ]: 1727 : SupportAnalyzer* sa = is_orig ? orig_supporters : resp_supporters;
1954 [ + + ]: 2444 : for ( ; sa; sa = sa->Sibling() )
1955 : 717 : static_cast<TCP_SupportAnalyzer*>(sa)->EndpointEOF(is_orig);
1956 : 1727 : }
1957 : :
1958 : 1727 : void TCP_ApplicationAnalyzer::TraceRewriterEOF(bool is_orig)
1959 : : {
1960 [ + + ]: 1727 : SupportAnalyzer* sa = is_orig ? orig_supporters : resp_supporters;
1961 [ + + ]: 2444 : for ( ; sa; sa = sa->Sibling() )
1962 : 717 : static_cast<TCP_SupportAnalyzer*>(sa)->TraceRewriterEOF(is_orig);
1963 : 1727 : }
1964 : :
1965 : : void TCP_ApplicationAnalyzer::ConnectionClosed(TCP_Endpoint* endpoint,
1966 : 1836 : TCP_Endpoint* peer, int gen_event)
1967 : : {
1968 : : SupportAnalyzer* sa =
1969 [ + + ]: 1836 : endpoint->IsOrig() ? orig_supporters : resp_supporters;
1970 : :
1971 [ + + ]: 2579 : for ( ; sa; sa = sa->Sibling() )
1972 : : static_cast<TCP_SupportAnalyzer*>(sa)
1973 : 743 : ->ConnectionClosed(endpoint, peer, gen_event);
1974 : 1836 : }
1975 : :
1976 : 667 : void TCP_ApplicationAnalyzer::ConnectionFinished(int half_finished)
1977 : : {
1978 [ + + ]: 939 : for ( SupportAnalyzer* sa = orig_supporters; sa; sa = sa->Sibling() )
1979 : : static_cast<TCP_SupportAnalyzer*>(sa)
1980 : 272 : ->ConnectionFinished(half_finished);
1981 : :
1982 [ + + ]: 939 : for ( SupportAnalyzer* sa = resp_supporters; sa; sa = sa->Sibling() )
1983 : : static_cast<TCP_SupportAnalyzer*>(sa)
1984 : 272 : ->ConnectionFinished(half_finished);
1985 : 667 : }
1986 : :
1987 : 91 : void TCP_ApplicationAnalyzer::ConnectionReset()
1988 : : {
1989 [ + + ]: 132 : for ( SupportAnalyzer* sa = orig_supporters; sa; sa = sa->Sibling() )
1990 : 41 : static_cast<TCP_SupportAnalyzer*>(sa)->ConnectionReset();
1991 : :
1992 [ + + ]: 132 : for ( SupportAnalyzer* sa = resp_supporters; sa; sa = sa->Sibling() )
1993 : 41 : static_cast<TCP_SupportAnalyzer*>(sa)->ConnectionReset();
1994 : 91 : }
1995 : :
1996 : 312 : void TCP_ApplicationAnalyzer::PacketWithRST()
1997 : : {
1998 [ + + ]: 443 : for ( SupportAnalyzer* sa = orig_supporters; sa; sa = sa->Sibling() )
1999 : 131 : static_cast<TCP_SupportAnalyzer*>(sa)->PacketWithRST();
2000 : :
2001 [ + + ]: 443 : for ( SupportAnalyzer* sa = resp_supporters; sa; sa = sa->Sibling() )
2002 : 131 : static_cast<TCP_SupportAnalyzer*>(sa)->PacketWithRST();
2003 : 312 : }
2004 : :
2005 : 0 : TCPStats_Endpoint::TCPStats_Endpoint(TCP_Endpoint* e)
2006 : : {
2007 : 0 : endp = e;
2008 : 0 : num_pkts = 0;
2009 : 0 : num_rxmit = 0;
2010 : 0 : num_rxmit_bytes = 0;
2011 : 0 : num_in_order = 0;
2012 : 0 : num_OO = 0;
2013 : 0 : num_repl = 0;
2014 : 0 : max_top_seq = 0;
2015 : 0 : last_id = 0;
2016 : 0 : endian_type = ENDIAN_UNKNOWN;
2017 : 0 : }
2018 : :
2019 : 0 : int endian_flip(int n)
2020 : : {
2021 : 0 : return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
2022 : : }
2023 : :
2024 : : int TCPStats_Endpoint::DataSent(double /* t */, int seq, int len, int caplen,
2025 : : const u_char* /* data */,
2026 : 0 : const IP_Hdr* ip, const struct tcphdr* /* tp */)
2027 : : {
2028 [ # # ]: 0 : if ( ++num_pkts == 1 )
2029 : : { // First packet.
2030 : 0 : last_id = ntohs(ip->ID4());
2031 : 0 : return 0;
2032 : : }
2033 : :
2034 : 0 : int id = ntohs(ip->ID4());
2035 : :
2036 [ # # ]: 0 : if ( id == last_id )
2037 : : {
2038 : 0 : ++num_repl;
2039 : 0 : return 0;
2040 : : }
2041 : :
2042 : 0 : short id_delta = id - last_id;
2043 : 0 : short id_endian_delta = endian_flip(id) - endian_flip(last_id);
2044 : :
2045 : 0 : int abs_id_delta = id_delta > 0 ? id_delta : -id_delta;
2046 : : int abs_id_endian_delta =
2047 : 0 : id_endian_delta > 0 ? id_endian_delta : -id_endian_delta;
2048 : :
2049 : : int final_id_delta;
2050 : :
2051 [ # # ]: 0 : if ( abs_id_delta < abs_id_endian_delta )
2052 : : { // Consistent with big-endian.
2053 [ # # ]: 0 : if ( endian_type == ENDIAN_UNKNOWN )
2054 : 0 : endian_type = ENDIAN_BIG;
2055 [ # # ]: 0 : else if ( endian_type == ENDIAN_BIG )
2056 : : ;
2057 : : else
2058 : 0 : endian_type = ENDIAN_CONFUSED;
2059 : :
2060 : 0 : final_id_delta = id_delta;
2061 : : }
2062 : : else
2063 : : { // Consistent with little-endian.
2064 [ # # ]: 0 : if ( endian_type == ENDIAN_UNKNOWN )
2065 : 0 : endian_type = ENDIAN_LITTLE;
2066 [ # # ]: 0 : else if ( endian_type == ENDIAN_LITTLE )
2067 : : ;
2068 : : else
2069 : 0 : endian_type = ENDIAN_CONFUSED;
2070 : :
2071 : 0 : final_id_delta = id_endian_delta;
2072 : : }
2073 : :
2074 [ # # ][ # # ]: 0 : if ( final_id_delta < 0 && final_id_delta > -256 )
2075 : : {
2076 : 0 : ++num_OO;
2077 : 0 : return 0;
2078 : : }
2079 : :
2080 : 0 : last_id = id;
2081 : :
2082 : 0 : ++num_in_order;
2083 : :
2084 : 0 : int top_seq = seq + len;
2085 : :
2086 : 0 : int data_in_flight = endp->LastSeq() - endp->AckSeq();
2087 [ # # ]: 0 : if ( data_in_flight < 0 )
2088 : 0 : data_in_flight = 0;
2089 : :
2090 : 0 : int seq_delta = top_seq - max_top_seq;
2091 [ # # ]: 0 : if ( seq_delta <= 0 )
2092 : : {
2093 [ # # ][ # # ]: 0 : if ( ! ignore_keep_alive_rexmit || len > 1 || data_in_flight > 0 )
[ # # ]
2094 : : {
2095 : 0 : ++num_rxmit;
2096 : 0 : num_rxmit_bytes += len;
2097 : : }
2098 : :
2099 : 0 : DEBUG_MSG("%.6f rexmit %d + %d <= %d data_in_flight = %d\n",
2100 : : network_time, seq, len, max_top_seq, data_in_flight);
2101 : :
2102 [ # # ]: 0 : if ( tcp_rexmit )
2103 : : {
2104 : 0 : val_list* vl = new val_list();
2105 : 0 : vl->append(endp->TCP()->BuildConnVal());
2106 : 0 : vl->append(new Val(endp->IsOrig(), TYPE_BOOL));
2107 : 0 : vl->append(new Val(seq, TYPE_COUNT));
2108 : 0 : vl->append(new Val(len, TYPE_COUNT));
2109 : 0 : vl->append(new Val(data_in_flight, TYPE_COUNT));
2110 : 0 : vl->append(new Val(endp->peer->window, TYPE_COUNT));
2111 : :
2112 : 0 : endp->TCP()->ConnectionEvent(tcp_rexmit, vl);
2113 : : }
2114 : : }
2115 : : else
2116 : 0 : max_top_seq = top_seq;
2117 : :
2118 : 0 : return 0;
2119 : : }
2120 : :
2121 : 0 : RecordVal* TCPStats_Endpoint::BuildStats()
2122 : : {
2123 : 0 : RecordVal* stats = new RecordVal(endpoint_stats);
2124 : :
2125 : 0 : stats->Assign(0, new Val(num_pkts,TYPE_COUNT));
2126 : 0 : stats->Assign(1, new Val(num_rxmit,TYPE_COUNT));
2127 : 0 : stats->Assign(2, new Val(num_rxmit_bytes,TYPE_COUNT));
2128 : 0 : stats->Assign(3, new Val(num_in_order,TYPE_COUNT));
2129 : 0 : stats->Assign(4, new Val(num_OO,TYPE_COUNT));
2130 : 0 : stats->Assign(5, new Val(num_repl,TYPE_COUNT));
2131 : 0 : stats->Assign(6, new Val(endian_type,TYPE_COUNT));
2132 : :
2133 : 0 : return stats;
2134 : : }
2135 : :
2136 : 0 : TCPStats_Analyzer::TCPStats_Analyzer(Connection* c)
2137 : 0 : : TCP_ApplicationAnalyzer(AnalyzerTag::TCPStats, c)
2138 : : {
2139 : 0 : }
2140 : :
2141 : 0 : TCPStats_Analyzer::~TCPStats_Analyzer()
2142 : : {
2143 : 0 : delete orig_stats;
2144 : 0 : delete resp_stats;
2145 [ # # ][ # # ]: 0 : }
[ # # ]
2146 : :
2147 : 0 : void TCPStats_Analyzer::Init()
2148 : : {
2149 : 0 : TCP_ApplicationAnalyzer::Init();
2150 : :
2151 : 0 : orig_stats = new TCPStats_Endpoint(TCP()->Orig());
2152 : 0 : resp_stats = new TCPStats_Endpoint(TCP()->Resp());
2153 : 0 : }
2154 : :
2155 : 0 : void TCPStats_Analyzer::Done()
2156 : : {
2157 : 0 : TCP_ApplicationAnalyzer::Done();
2158 : :
2159 : 0 : val_list* vl = new val_list;
2160 : 0 : vl->append(BuildConnVal());
2161 : 0 : vl->append(orig_stats->BuildStats());
2162 : 0 : vl->append(resp_stats->BuildStats());
2163 : 0 : ConnectionEvent(conn_stats, vl);
2164 : 0 : }
2165 : :
2166 : 0 : void TCPStats_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, int seq, const IP_Hdr* ip, int caplen)
2167 : : {
2168 : 0 : TCP_ApplicationAnalyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);
2169 : :
2170 [ # # ]: 0 : if ( is_orig )
2171 : 0 : orig_stats->DataSent(network_time, seq, len, caplen, data, ip, 0);
2172 : : else
2173 : 0 : resp_stats->DataSent(network_time, seq, len, caplen, data, ip, 0);
2174 [ + - ][ + - ]: 6 : }
|