PrintingStatus format_data(ctsConfig::StatusFormatting _format, long long _current_time, bool _clear_status) throw() { ctsTcpStatistics tcp_data(ctsConfig::Settings->TcpStatusDetails.snap_view(_clear_status)); ctsConnectionStatistics connection_data(ctsConfig::Settings->ConnectionStatusDetails.snap_view(_clear_status)); long long time_elapsed = tcp_data.end_time.get() - tcp_data.start_time.get(); if (_format == ctsConfig::StatusFormatting::Csv) { unsigned long characters_written = 0; // converting milliseconds to seconds before printing characters_written += this->append_csvoutput(characters_written, TimeSliceLength, static_cast<float>(_current_time / 1000.0)); // calculating # of bytes that were sent between the previous format() and current call to format() characters_written += this->append_csvoutput( characters_written, SendBytesPerSecondLength, (time_elapsed > 0LL) ? static_cast<unsigned long>(tcp_data.bytes_sent.get() * 1000LL / time_elapsed) : 0LL); // calculating # of bytes that were received between the previous format() and current call to format() characters_written += this->append_csvoutput( characters_written, RecvBytesPerSecondLength, (time_elapsed > 0LL) ? static_cast<unsigned long>(tcp_data.bytes_recv.get() * 1000LL / time_elapsed) : 0LL); characters_written += this->append_csvoutput(characters_written, CurrentTransactionsLength, connection_data.active_connection_count.get()); characters_written += this->append_csvoutput(characters_written, CompletedTransactionsLength, connection_data.successful_completion_count.get()); characters_written += this->append_csvoutput(characters_written, ConnectionErrorsLength, connection_data.connection_error_count.get()); characters_written += this->append_csvoutput(characters_written, ProtocolErrorsLength, connection_data.protocol_error_count.get(), false); // no comma at the end this->terminate_string(characters_written); } else { // converting milliseconds to seconds before printing this->right_justify_output(TimeSliceOffset, TimeSliceLength, static_cast<float>(_current_time / 1000.0)); // calculating # of bytes that were sent between the previous format() and current call to format() this->right_justify_output( SendBytesPerSecondOffset, SendBytesPerSecondLength, (time_elapsed > 0LL) ? static_cast<unsigned long>(tcp_data.bytes_sent.get() * 1000LL / time_elapsed) : 0LL); // calculating # of bytes that were received between the previous format() and current call to format() this->right_justify_output( RecvBytesPerSecondOffset, RecvBytesPerSecondLength, (time_elapsed > 0LL) ? static_cast<unsigned long>(tcp_data.bytes_recv.get() * 1000LL / time_elapsed) : 0LL); this->right_justify_output(CurrentTransactionsOffset, CurrentTransactionsLength, connection_data.active_connection_count.get()); this->right_justify_output(CompletedTransactionsOffset, CompletedTransactionsLength, connection_data.successful_completion_count.get()); this->right_justify_output(ConnectionErrorsOffset, ConnectionErrorsLength, connection_data.connection_error_count.get()); this->right_justify_output(ProtocolErrorsOffset, ProtocolErrorsLength, connection_data.protocol_error_count.get()); this->terminate_string(ProtocolErrorsOffset); } return PrintComplete; }
void process_tcp(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length) { struct { unsigned src_port; unsigned dst_port; unsigned seqno; unsigned ackno; unsigned header_length; unsigned flags; unsigned window; unsigned checksum; unsigned urgent; } tcp; ferret->statistics.tcp++; if (length == 0) { FRAMERR(frame, "tcp: frame empty\n"); return; } if (length < 20) { FRAMERR(frame, "tcp: frame too short\n"); return; } /* 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | data | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ tcp.src_port = ex16be(px+0); tcp.dst_port = ex16be(px+2); tcp.seqno = ex32be(px+4); tcp.ackno = ex32be(px+8); tcp.header_length = px[12]>>2; tcp.flags = px[13]; tcp.window = ex16be(px+14); tcp.checksum = ex16be(px+16); tcp.urgent = ex16be(px+18); frame->src_port = tcp.src_port; frame->dst_port = tcp.dst_port; if (tcp.header_length < 20) { /* Regress: defcon2008\dump027.pcap(39901) */ //FRAMERR(frame, "tcp: header too short, expected length=20, found length=%d\n", tcp.header_length); return; } if (tcp.header_length > length) { //FRAMERR(frame, "tcp: header too short, expected length=%d, found length=%d\n", tcp.header_length, length); return; } if ((tcp.flags & 0x20) && tcp.urgent > 0) { FRAMERR(frame, "tcp: found %d bytes of urgent data\n", tcp.urgent); return; } /* Check the checksum */ if (!validate_tcp_checksum(px, length, frame->src_ipv4, frame->dst_ipv4)) { /* Regress: defcon2008-msnmsgr.pcap(24066) */ ferret->statistics.errs_tcp_checksum++; return; } /*TODO: need to check checksum */ if (tcp.header_length > 20) { unsigned o = 20; unsigned max = tcp.header_length; while (o < tcp.header_length) { unsigned tag = px[o++]; unsigned len; if (tag == 0) break; if (tag == 1) continue; if (o >= max) { FRAMERR(frame, "tcp: options too long\n"); break; } len = px[o++]; if (len < 2) { FRAMERR(frame, "tcp: invalid length field\n"); break; } if (o+len-2 > max) { FRAMERR(frame, "tcp: options too long\n"); break; } switch (tag) { case 0x02: /* max seg size */ if (len != 4) FRAMERR(frame, "tcp: unknown length: option=%d, length=%d\n", tag, len); break; case 0x04: /* SACK permitted */ if (len != 2) FRAMERR(frame, "tcp: unknown length: option=%d, length=%d\n", tag, len); break; case 0x05: /* SACK */ break; case 0x08: /*timestamp*/ break; case 0x03: /*window scale*/ break; default: FRAMERR(frame, "tcp: unknown option=%d, length=%d\n", tag, len); } o += len-2; } } SAMPLE(ferret,"TCP", JOT_NUM("flags", tcp.flags)); /* Process an "acknowledgement". Among other things, this will identify * when packets have been missed: if the other side claims to have * received a packet, but we never saw it, then we know that it was * dropped somewhere on the network (probably because we are getting * a weak signal via wireless). */ if (tcp.flags & TCP_ACK) { tcp_ack_data(ferret, frame, tcp.ackno); } switch (tcp.flags & 0x3F) { case TCP_SYN: tcp_syn(ferret, frame); break; case TCP_SYN|TCP_ACK: tcp_synack(ferret, frame); break; case TCP_FIN: case TCP_FIN|TCP_ACK: case TCP_FIN|TCP_ACK|TCP_PSH: tcp_fin(ferret, frame); break; case TCP_ACK: case TCP_ACK|TCP_PSH: if (length > tcp.header_length) tcp_data(ferret, frame, px+tcp.header_length, length-tcp.header_length, tcp.seqno, tcp.ackno); break; case TCP_RST: case TCP_RST|TCP_ACK: break; case 0x40|TCP_ACK: break; case TCP_RST|TCP_ACK|TCP_FIN: case TCP_RST|TCP_ACK|TCP_PSH: break; default: FRAMERR(frame, "tcp: unexpected combo of flags: 0x%03x\n", tcp.flags); } }