// test harness for protocol parsing #include <iostream> // cout, cerr #include <string> #include "data_structures/basic_types.h" // Timeval #include "data_structures/PacketFilter.h" #include "data_structures/Aggregate.h" // Trace #include "protocols/parsers/QcapAdaptor.h" #include "data_structures/Packet.h" #include "data_structures/Clock.h" #include "data_structures/StreamListener.h" #include "protocols/parsers/IPv4Sessionizer.h" // for TCP and UDP #include "attributes/ByteCountAttribute.h" #include "attributes/DurationAttribute.h" #include "attributes/ArithmeticAttribute.h" #include "attributes/HistogramAttribute.h" #include "attributes/PacketCountAttribute.h" #include "attributes/ConversationTrackerAttribute.h" #include "attributes/MemoryAttribute.h" #include <sys/times.h> // CPU times for profiling using namespace std; int lengthBounds[23] = { 0, 1, 2, 4, 5, 9, 19, 39, 49, 99, 179, 235, 268, 349, 449, 515, 548, 649, 999, 1379, 1380, 1431, 1472 }; Timeval delayBounds[8] = { Timeval( 0.000001 ), Timeval( 0.0001 ), Timeval( 0.001 ), Timeval( 0.01 ), Timeval( 0.1 ), Timeval( 1.0 ), Timeval( 10.0 ), Timeval( 64.0 ) }; int usage( void ) { cerr << "Usage: profile_streams_thesis [-l] <pcap>" << endl; cerr << endl; cerr << "\t" "-l : list packets - time, delay, and payload length" << endl; return 0; } void initStreamAttributes( Decomposition& templ, Clock& clock ) { PacketFilter *nonemptyPacketFilter = new SimplePacketFilter( PacketAttribute("transport.len"), ConcretePacketAttributeValue<int>(0), SimplePacketFilter::GREATER ); // begin time templ.addAttrib( "start_time", PacketDrivenMemoryAttribute<Timeval>( "frame.time", MemoryAttribute<Timeval>::ATTRIB_TYPE_PACKET, 1, false ) ); // duration templ.addAttrib( "duration", DurationAttribute() ); // packet counts // packet count pkt_count is implicit templ.addAttrib( "nonempty_count", PacketCountAttribute( *nonemptyPacketFilter ) ); // byte counts templ.addAttrib( "pkt_byte_count", ByteCountAttribute(true) ); templ.addAttrib( "payload_byte_count", ByteCountAttribute(false) ); // mean inter-packet delay templ.addAttrib( "mean_delay", ArithmeticAttribute<Timeval,int,double>( "duration", "pkt_count", ArithmeticAttribute<Timeval,int,double>::OP_DIVIDE ), 1 ); // mean packet lengths templ.addAttrib( "mean_pkt_len", ArithmeticAttribute<int,int,double>( "pkt_byte_count", "pkt_count", ArithmeticAttribute<Timeval,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "mean_payload_len", ArithmeticAttribute<int,int,double>( "payload_byte_count", "pkt_count", ArithmeticAttribute<Timeval,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "mean_nonempty_payload_len", ArithmeticAttribute<int,int,double>( "payload_byte_count", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // databyte ratio originator to responder templ.addAttrib( "payload_byte_count_fwd_plus1", ArithmeticAttribute<int,int,int>( "payload_byte_count.forward", 1, ArithmeticAttribute<int,int,int>::OP_ADD ), 1 ); templ.addAttrib( "payload_byte_count_rev_plus1", ArithmeticAttribute<int,int,int>( "payload_byte_count.reverse", 1, ArithmeticAttribute<int,int,int>::OP_ADD ), 1 ); templ.addAttrib( "dir_data", ArithmeticAttribute<int,int,double>( "payload_byte_count_fwd_plus1", "payload_byte_count_rev_plus1", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 2 ); templ.addAttrib( "mean_pkt_datarate", ArithmeticAttribute<int,Timeval,double>( "pkt_byte_count", "duration", ArithmeticAttribute<int,Timeval,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "mean_payload_datarate", ArithmeticAttribute<int,Timeval,double>( "payload_byte_count", "duration", ArithmeticAttribute<int,Timeval,double>::OP_DIVIDE ), 1 ); // max datarate attributes // 1s templ.addAttrib( "1s_payload_len_window", PacketDrivenMemoryAttribute<int>( "transport.len", MemoryAttribute<int>::ATTRIB_TYPE_PACKET, Timeval(1.0) ) ); templ.addAttrib( "1s_datarate", ArithmeticAttribute<int,double,double>( "1s_payload_len_window.sum", 1.0, ArithmeticAttribute<int,double,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "1s_datarate_window", SampledMemoryAttribute<double>( "1s_datarate", SampledMemoryAttribute<double>::ATTRIB_TYPE_AGGREGATE, 0, Timeval(0.2) ) ); // 5s templ.addAttrib( "5s_payload_len_window", PacketDrivenMemoryAttribute<int>( "transport.len", MemoryAttribute<int>::ATTRIB_TYPE_PACKET, Timeval(5.0) ) ); templ.addAttrib( "5s_datarate", ArithmeticAttribute<int,double,double>( "5s_payload_len_window.sum", 5.0, ArithmeticAttribute<int,double,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "5s_datarate_window", SampledMemoryAttribute<double>( "5s_datarate", SampledMemoryAttribute<double>::ATTRIB_TYPE_AGGREGATE, 0, Timeval(1.0) ) ); // 30s templ.addAttrib( "30s_payload_len_window", PacketDrivenMemoryAttribute<int>( "transport.len", MemoryAttribute<int>::ATTRIB_TYPE_PACKET, Timeval(30.0) ) ); templ.addAttrib( "30s_datarate", ArithmeticAttribute<int,double,double>( "30s_payload_len_window.sum", 30.0, ArithmeticAttribute<int,double,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "30s_datarate_window", SampledMemoryAttribute<double>( "30s_datarate", SampledMemoryAttribute<double>::ATTRIB_TYPE_AGGREGATE, 0, Timeval(6.0) ) ); // packet flag heuristics templ.addAttrib( "urg_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.urg"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_urg", ArithmeticAttribute<int,int,double>( "urg_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "ack_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.ack"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_ack", ArithmeticAttribute<int,int,double>( "ack_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "psh_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.psh"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_psh", ArithmeticAttribute<int,int,double>( "psh_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "rst_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.rst"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_rst", ArithmeticAttribute<int,int,double>( "rst_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "syn_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.syn"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_syn", ArithmeticAttribute<int,int,double>( "syn_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "fin_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.fin"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_fin", ArithmeticAttribute<int,int,double>( "fin_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); /* // tracker for conversations templ.addAttrib( "conv_tracker", ConversationTrackerAttribute( *nonemptyPacketFilter, 2, // minimum 2 datagrams per exchange 2 ) ); // minimum 2 exchanges per conversation // tracker for sustained conversations templ.addAttrib( "sust_conv_tracker", ConversationTrackerAttribute( *nonemptyPacketFilter, 2, // minimum 2 datagrams per exchange 3 ) ); // minimum 3 exchanges per sustained conversation // conversation indicator alpha templ.addAttrib( "conv_alpha", ArithmeticAttribute<int,int,double>( "conv_tracker.datagram_count", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // conversation indicator beta templ.addAttrib( "conv_beta", ArithmeticAttribute<int,int,double>( "sust_conv_tracker.datagram_count", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // conversation indicator gamma templ.addAttrib( "conv_gamma", ArithmeticAttribute<int,int,double>( "conv_tracker.forward_datagram_count", "conv_tracker.datagram_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // the transaction indicator is a sum of the number of changes in direction, so first we need to // track everything as a conversation templ.addAttrib( "trans_tracker", ConversationTrackerAttribute( *nonemptyPacketFilter, 1, 1 ) ); // transaction indicator templ.addAttrib( "trans_ind", ArithmeticAttribute<int,int,double>( "trans_tracker.dir_change_count", "trans_tracker.max_dir_change_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); */ delete nonemptyPacketFilter; } void initHalfstreamAttributes( Trace& templ, Clock& clock ) { templ.addAttrib( "duration", DurationAttribute() ); templ.addAttrib( "pkt_byte_count", ByteCountAttribute(true) ); templ.addAttrib( "payload_byte_count", ByteCountAttribute(false) ); // mean inter-packet delay templ.addAttrib( "mean_delay", ArithmeticAttribute<Timeval,int,double>( "duration", "pkt_count", ArithmeticAttribute<Timeval,int,double>::OP_DIVIDE ), 1 ); // empty and nonempty packet counts PacketFilter *nonemptyPacketFilter = new SimplePacketFilter( PacketAttribute("transport.len"), ConcretePacketAttributeValue<int>(0), SimplePacketFilter::GREATER ); templ.addAttrib( "nonempty_count", PacketCountAttribute( *nonemptyPacketFilter ) ); templ.addAttrib( "empty_count", ArithmeticAttribute<int,int,int>( "pkt_count", "nonempty_count", ArithmeticAttribute<int,int,int>::OP_SUBTRACT ), 1 ); // mean packet lengths templ.addAttrib( "mean_pkt_len", ArithmeticAttribute<int,int,double>( "pkt_byte_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "mean_payload_len", ArithmeticAttribute<int,int,double>( "payload_byte_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "mean_nonempty_payload_len", ArithmeticAttribute<int,int,double>( "payload_byte_count", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // max datarate attributes // 1s templ.addAttrib( "1s_payload_len_window", PacketDrivenMemoryAttribute<int>( "transport.len", MemoryAttribute<int>::ATTRIB_TYPE_PACKET, Timeval(1.0) ) ); templ.addAttrib( "1s_datarate", ArithmeticAttribute<int,double,double>( "1s_payload_len_window.sum", 1.0, ArithmeticAttribute<int,double,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "1s_datarate_window", SampledMemoryAttribute<double>( "1s_datarate", SampledMemoryAttribute<double>::ATTRIB_TYPE_AGGREGATE, 0, Timeval(0.2) ) ); // 5s templ.addAttrib( "5s_payload_len_window", PacketDrivenMemoryAttribute<int>( "transport.len", MemoryAttribute<int>::ATTRIB_TYPE_PACKET, Timeval(5.0) ) ); templ.addAttrib( "5s_datarate", ArithmeticAttribute<int,double,double>( "5s_payload_len_window.sum", 5.0, ArithmeticAttribute<int,double,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "5s_datarate_window", SampledMemoryAttribute<double>( "5s_datarate", SampledMemoryAttribute<double>::ATTRIB_TYPE_AGGREGATE, 0, Timeval(1.0) ) ); // 30s templ.addAttrib( "30s_payload_len_window", PacketDrivenMemoryAttribute<int>( "transport.len", MemoryAttribute<int>::ATTRIB_TYPE_PACKET, Timeval(30.0) ) ); templ.addAttrib( "30s_datarate", ArithmeticAttribute<int,double,double>( "30s_payload_len_window.sum", 30.0, ArithmeticAttribute<int,double,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "30s_datarate_window", SampledMemoryAttribute<double>( "30s_datarate", SampledMemoryAttribute<double>::ATTRIB_TYPE_AGGREGATE, 0, Timeval(6.0) ) ); // small packet filters - parameter set 1 (20bytes, 10ms, 2000ms) PacketFilter *sp_filter_1 = new CompoundPacketFilter( SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(20), SimplePacketFilter::LESS_OR_EQUAL ), *nonemptyPacketFilter, CompoundPacketFilter::AND ); templ.addAttrib( "sp_count_1", PacketCountAttribute( *sp_filter_1 ) ); // small and empty packets : sp_count + empty_count templ.addAttrib( "sep_count_1", ArithmeticAttribute<int,int,int>( "sp_count_1", "empty_count", ArithmeticAttribute<int,int,int>::OP_ADD ), 2 ); // consecutive small packets PacketFilter *csp_filter_1 = new CompoundPacketFilter( *sp_filter_1, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); templ.addAttrib( "csp_count_1", PacketCountAttribute( *csp_filter_1 ) ); PacketFilter *sp_delay_filter_1 = new CompoundPacketFilter( /* 10ms <= frame.time_delta <= 2000ms */ SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.010)), SimplePacketFilter::GREATER_OR_EQUAL ), SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(2.000)), SimplePacketFilter::LESS_OR_EQUAL ), CompoundPacketFilter::AND ); templ.addAttrib( "csp_delay_count_1", PacketCountAttribute( CompoundPacketFilter( *csp_filter_1, *sp_delay_filter_1, CompoundPacketFilter::AND ) ) ); templ.addAttrib( "sp_alpha_1", ArithmeticAttribute<int,int,double>( "csp_delay_count_1", "csp_count_1", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_beta_1", ArithmeticAttribute<int,int,double>( "sp_count_1", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_gamma_1", ArithmeticAttribute<int,int,double>( "csp_count_1", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_delta_1", ArithmeticAttribute<int,int,double>( "csp_count_1", "sep_count_1", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 3 /*sep_count_1 is tier 2*/ ); // small packet filters - parameter set 2 (60bytes, 25ms, 3000ms) PacketFilter *sp_filter_2 = new CompoundPacketFilter( SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(60), SimplePacketFilter::LESS_OR_EQUAL ), *nonemptyPacketFilter, CompoundPacketFilter::AND ); templ.addAttrib( "sp_count_2", PacketCountAttribute( *sp_filter_2 ) ); // small and empty packets : sp_count + empty_count templ.addAttrib( "sep_count_2", ArithmeticAttribute<int,int,int>( "sp_count_2", "empty_count", ArithmeticAttribute<int,int,int>::OP_ADD ), 2 ); // consecutive small packets PacketFilter *csp_filter_2 = new CompoundPacketFilter( *sp_filter_2, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); templ.addAttrib( "csp_count_2", PacketCountAttribute( *csp_filter_2 ) ); PacketFilter *sp_delay_filter_2 = new CompoundPacketFilter( /* 25ms <= frame.time_delta <= 3000ms */ SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.025)), SimplePacketFilter::GREATER_OR_EQUAL ), SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(3.000)), SimplePacketFilter::LESS_OR_EQUAL ), CompoundPacketFilter::AND ); templ.addAttrib( "csp_delay_count_2", PacketCountAttribute( CompoundPacketFilter( *csp_filter_2, *sp_delay_filter_2, CompoundPacketFilter::AND ) ) ); templ.addAttrib( "sp_alpha_2", ArithmeticAttribute<int,int,double>( "csp_delay_count_2", "csp_count_2", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_beta_2", ArithmeticAttribute<int,int,double>( "sp_count_2", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_gamma_2", ArithmeticAttribute<int,int,double>( "csp_count_2", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_delta_2", ArithmeticAttribute<int,int,double>( "csp_count_2", "sep_count_2", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 3 /*sep_count_2 is tier 2*/ ); // small packet filters - parameter set 3 (200bytes, 250ms, 30000ms) PacketFilter *sp_filter_3 = new CompoundPacketFilter( SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(200), SimplePacketFilter::LESS_OR_EQUAL ), *nonemptyPacketFilter, CompoundPacketFilter::AND ); templ.addAttrib( "sp_count_3", PacketCountAttribute( *sp_filter_3 ) ); // small and empty packets : sp_count + empty_count templ.addAttrib( "sep_count_3", ArithmeticAttribute<int,int,int>( "sp_count_3", "empty_count", ArithmeticAttribute<int,int,int>::OP_ADD ), 2 ); // consecutive small packets PacketFilter *csp_filter_3 = new CompoundPacketFilter( *sp_filter_3, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); templ.addAttrib( "csp_count_3", PacketCountAttribute( *csp_filter_3 ) ); PacketFilter *sp_delay_filter_3 = new CompoundPacketFilter( /* 250ms <= frame.time_delta <= 30000ms */ SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.250)), SimplePacketFilter::GREATER_OR_EQUAL ), SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(30.000)), SimplePacketFilter::LESS_OR_EQUAL ), CompoundPacketFilter::AND ); templ.addAttrib( "csp_delay_count_3", PacketCountAttribute( CompoundPacketFilter( *csp_filter_3, *sp_delay_filter_3, CompoundPacketFilter::AND ) ) ); templ.addAttrib( "sp_alpha_3", ArithmeticAttribute<int,int,double>( "csp_delay_count_3", "csp_count_3", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_beta_3", ArithmeticAttribute<int,int,double>( "sp_count_3", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_gamma_3", ArithmeticAttribute<int,int,double>( "csp_count_3", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "sp_delta_3", ArithmeticAttribute<int,int,double>( "csp_count_3", "sep_count_3", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 3 /*sep_count_2 is tier 2*/ ); // large packet heuristics - parameter set 1 ( 225 bytes, 50ms ) PacketFilter *lp_filter_1 = new SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(225), SimplePacketFilter::GREATER_OR_EQUAL ); PacketFilter *clp_filter_1 = new CompoundPacketFilter( *lp_filter_1, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); // file transfer - 50ms delay or less PacketFilter *lp_delay_filter_1 = new SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.050)), SimplePacketFilter::LESS_OR_EQUAL ); PacketFilter *clp_delay_filter_1 = new CompoundPacketFilter( *clp_filter_1, *lp_delay_filter_1, CompoundPacketFilter::AND ); templ.addAttrib( "lp_count_1", PacketCountAttribute( *lp_filter_1 ) ); // consecutive big packets templ.addAttrib( "clp_count_1", PacketCountAttribute( *clp_filter_1 ) ); // consecutive big packets with file-transfer-range delay templ.addAttrib( "clp_delay_count_1", PacketCountAttribute( *clp_delay_filter_1 ) ); templ.addAttrib( "lp_alpha_1", ArithmeticAttribute<int,int,double>( "clp_delay_count_1", "clp_count_1", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_beta_1", ArithmeticAttribute<int,int,double>( "lp_count_1", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_gamma_1", ArithmeticAttribute<int,int,double>( "clp_count_1", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // large packet heuristics - parameter set 2 ( 1000 bytes, 50ms ) PacketFilter *lp_filter_2 = new SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(1000), SimplePacketFilter::GREATER_OR_EQUAL ); PacketFilter *clp_filter_2 = new CompoundPacketFilter( *lp_filter_2, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); // file transfer - 50ms delay or less PacketFilter *lp_delay_filter_2 = new SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.050)), SimplePacketFilter::LESS_OR_EQUAL ); PacketFilter *clp_delay_filter_2 = new CompoundPacketFilter( *clp_filter_2, *lp_delay_filter_2, CompoundPacketFilter::AND ); templ.addAttrib( "lp_count_2", PacketCountAttribute( *lp_filter_2 ) ); // consecutive big packets templ.addAttrib( "clp_count_2", PacketCountAttribute( *clp_filter_2 ) ); // consecutive big packets with file-transfer-range delay templ.addAttrib( "clp_delay_count_2", PacketCountAttribute( *clp_delay_filter_2 ) ); templ.addAttrib( "lp_alpha_2", ArithmeticAttribute<int,int,double>( "clp_delay_count_2", "clp_count_2", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_beta_2", ArithmeticAttribute<int,int,double>( "lp_count_2", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_gamma_2", ArithmeticAttribute<int,int,double>( "clp_count_2", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // large packet heuristics - parameter set 3 ( 1460 bytes, 50ms ) PacketFilter *lp_filter_3 = new SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(1460), SimplePacketFilter::GREATER_OR_EQUAL ); PacketFilter *clp_filter_3 = new CompoundPacketFilter( *lp_filter_3, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); // file transfer - 50ms delay or less PacketFilter *lp_delay_filter_3 = new SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.050)), SimplePacketFilter::LESS_OR_EQUAL ); PacketFilter *clp_delay_filter_3 = new CompoundPacketFilter( *clp_filter_3, *lp_delay_filter_3, CompoundPacketFilter::AND ); templ.addAttrib( "lp_count_3", PacketCountAttribute( *lp_filter_3 ) ); // consecutive big packets templ.addAttrib( "clp_count_3", PacketCountAttribute( *clp_filter_3 ) ); // consecutive big packets with file-transfer-range delay templ.addAttrib( "clp_delay_count_3", PacketCountAttribute( *clp_delay_filter_3 ) ); templ.addAttrib( "lp_alpha_3", ArithmeticAttribute<int,int,double>( "clp_delay_count_3", "clp_count_3", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_beta_3", ArithmeticAttribute<int,int,double>( "lp_count_3", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_gamma_3", ArithmeticAttribute<int,int,double>( "clp_count_3", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // large packet heuristics - parameter set 4 ( 225 bytes, 250ms ) PacketFilter *lp_filter_4 = new SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(225), SimplePacketFilter::GREATER_OR_EQUAL ); PacketFilter *clp_filter_4 = new CompoundPacketFilter( *lp_filter_4, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); // file transfer - 250ms delay or less PacketFilter *lp_delay_filter_4 = new SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.250)), SimplePacketFilter::LESS_OR_EQUAL ); PacketFilter *clp_delay_filter_4 = new CompoundPacketFilter( *clp_filter_4, *lp_delay_filter_4, CompoundPacketFilter::AND ); templ.addAttrib( "lp_count_4", PacketCountAttribute( *lp_filter_4 ) ); // consecutive big packets templ.addAttrib( "clp_count_4", PacketCountAttribute( *clp_filter_4 ) ); // consecutive big packets with file-transfer-range delay templ.addAttrib( "clp_delay_count_4", PacketCountAttribute( *clp_delay_filter_4 ) ); templ.addAttrib( "lp_alpha_4", ArithmeticAttribute<int,int,double>( "clp_delay_count_4", "clp_count_4", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_beta_4", ArithmeticAttribute<int,int,double>( "lp_count_4", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_gamma_4", ArithmeticAttribute<int,int,double>( "clp_count_4", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // large packet heuristics - parameter set 5 ( 1000 bytes, 250ms ) PacketFilter *lp_filter_5 = new SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(1000), SimplePacketFilter::GREATER_OR_EQUAL ); PacketFilter *clp_filter_5 = new CompoundPacketFilter( *lp_filter_5, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); // file transfer - 250ms delay or less PacketFilter *lp_delay_filter_5 = new SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.250)), SimplePacketFilter::LESS_OR_EQUAL ); PacketFilter *clp_delay_filter_5 = new CompoundPacketFilter( *clp_filter_5, *lp_delay_filter_5, CompoundPacketFilter::AND ); templ.addAttrib( "lp_count_5", PacketCountAttribute( *lp_filter_5 ) ); // consecutive big packets templ.addAttrib( "clp_count_5", PacketCountAttribute( *clp_filter_5 ) ); // consecutive big packets with file-transfer-range delay templ.addAttrib( "clp_delay_count_5", PacketCountAttribute( *clp_delay_filter_5 ) ); templ.addAttrib( "lp_alpha_5", ArithmeticAttribute<int,int,double>( "clp_delay_count_5", "clp_count_5", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_beta_5", ArithmeticAttribute<int,int,double>( "lp_count_5", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_gamma_5", ArithmeticAttribute<int,int,double>( "clp_count_5", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // large packet heuristics - parameter set 6 ( 1460 bytes, 250ms ) PacketFilter *lp_filter_6 = new SimplePacketFilter( PacketAttribute( "transport.len" ), ConcretePacketAttributeValue<int>(1460), SimplePacketFilter::GREATER_OR_EQUAL ); PacketFilter *clp_filter_6 = new CompoundPacketFilter( *lp_filter_6, ConsecutivePacketFilter(), CompoundPacketFilter::AND ); // file transfer - 250ms delay or less PacketFilter *lp_delay_filter_6 = new SimplePacketFilter( PacketAttribute( "frame.time_delta" ), ConcretePacketAttributeValue<Timeval>(Timeval(0.250)), SimplePacketFilter::LESS_OR_EQUAL ); PacketFilter *clp_delay_filter_6 = new CompoundPacketFilter( *clp_filter_6, *lp_delay_filter_6, CompoundPacketFilter::AND ); templ.addAttrib( "lp_count_6", PacketCountAttribute( *lp_filter_6 ) ); // consecutive big packets templ.addAttrib( "clp_count_6", PacketCountAttribute( *clp_filter_6 ) ); // consecutive big packets with file-transfer-range delay templ.addAttrib( "clp_delay_count_6", PacketCountAttribute( *clp_delay_filter_6 ) ); templ.addAttrib( "lp_alpha_6", ArithmeticAttribute<int,int,double>( "clp_delay_count_6", "clp_count_6", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_beta_6", ArithmeticAttribute<int,int,double>( "lp_count_6", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "lp_gamma_6", ArithmeticAttribute<int,int,double>( "clp_count_6", "nonempty_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); // packet flag heuristics templ.addAttrib( "urg_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.urg"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_urg", ArithmeticAttribute<int,int,double>( "urg_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "ack_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.ack"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_ack", ArithmeticAttribute<int,int,double>( "ack_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "psh_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.psh"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_psh", ArithmeticAttribute<int,int,double>( "psh_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "rst_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.rst"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_rst", ArithmeticAttribute<int,int,double>( "rst_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "syn_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.syn"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_syn", ArithmeticAttribute<int,int,double>( "syn_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); templ.addAttrib( "fin_count", PacketCountAttribute( SimplePacketFilter( PacketAttribute("tcp.flags.fin"), ConcretePacketAttributeValue<int>(1), SimplePacketFilter::EQUAL ) ) ); templ.addAttrib( "flag_fin", ArithmeticAttribute<int,int,double>( "fin_count", "pkt_count", ArithmeticAttribute<int,int,double>::OP_DIVIDE ), 1 ); delete nonemptyPacketFilter; delete sp_filter_1; delete csp_filter_1; delete sp_delay_filter_1; delete sp_filter_2; delete csp_filter_2; delete sp_delay_filter_2; delete sp_filter_3; delete csp_filter_3; delete sp_delay_filter_3; delete lp_filter_1; delete clp_filter_1; delete lp_delay_filter_1; delete clp_delay_filter_1; delete lp_filter_2; delete clp_filter_2; delete lp_delay_filter_2; delete clp_delay_filter_2; delete lp_filter_3; delete clp_filter_3; delete lp_delay_filter_3; delete clp_delay_filter_3; delete lp_filter_4; delete clp_filter_4; delete lp_delay_filter_4; delete clp_delay_filter_4; delete lp_filter_5; delete clp_filter_5; delete lp_delay_filter_5; delete clp_delay_filter_5; delete lp_filter_6; delete clp_filter_6; delete lp_delay_filter_6; delete clp_delay_filter_6; } class StatsPrinter : public FilteredStreamListener { private: ostream& output; public: static const StreamEvent EXPIRING_STREAM_FILTER; public: StatsPrinter(void); StatsPrinter( ostream& out ); void printStream( const Decomposition& stream, bool csv_output = true, bool printout_packets = false ); virtual uint32_t handlePassedStreamEvent( const StreamEvent& e ); }; const StreamEvent StatsPrinter::EXPIRING_STREAM_FILTER( StreamEvent::STREAM_EXPIRING ); StatsPrinter::StatsPrinter(void) : FilteredStreamListener( EXPIRING_STREAM_FILTER ), output( cout ) { } StatsPrinter::StatsPrinter( ostream& out ) : FilteredStreamListener( EXPIRING_STREAM_FILTER ), output( out ) { } void StatsPrinter::printStream( const Decomposition& stream, bool csv_output, bool printout_packets ) { PacketAttribute pkttime( "frame.time" ); PacketAttribute timeDelta( "frame.time_delta" ); // output per-stream attributes if( csv_output ) { output << "\"s\""; try { const PacketDrivenMemoryAttribute<Timeval>& startTimeAttrib = dynamic_cast<const PacketDrivenMemoryAttribute<Timeval>&>(stream.getAttrib("start_time")); output << ", " << *(startTimeAttrib.begin()); } catch( bad_cast bce ) { output << ", \"error reading start_time\""; } output << ", \"" << stream.getStreamKey().toString() << "\""; output << ", " << stream.getAttrib("pkt_count"); output << ", " << dynamic_cast<const ScalarAttribute<Timeval>&>(stream.getAttrib("duration")).getValue().getDoubleValue(); output << ", " << stream.getAttrib("nonempty_count"); output << ", " << stream.getAttrib("pkt_byte_count"); output << ", " << stream.getAttrib("payload_byte_count"); output << ", " << stream.getAttrib("mean_delay"); output << ", " << stream.getAttrib("mean_pkt_len"); output << ", " << stream.getAttrib("mean_payload_len"); output << ", " << stream.getAttrib("mean_nonempty_payload_len"); output << ", " << stream.getAttrib("dir_data"); output << ", " << stream.getAttrib("mean_pkt_datarate"); output << ", " << stream.getAttrib("mean_payload_datarate"); output << ", " << stream.getAttrib("1s_datarate_window.max"); output << ", " << stream.getAttrib("5s_datarate_window.max"); output << ", " << stream.getAttrib("30s_datarate_window.max"); output << ", " << stream.getAttrib("flag_urg"); output << ", " << stream.getAttrib("flag_ack"); output << ", " << stream.getAttrib("flag_psh"); output << ", " << stream.getAttrib("flag_rst"); output << ", " << stream.getAttrib("flag_syn"); output << ", " << stream.getAttrib("flag_fin"); output << endl; } // could add an 'if proto is TCP or UDP' check here Decomposition::const_iterator halfstreamIt = stream.activeSubstreamsBegin(); while( halfstreamIt != stream.activeSubstreamsEnd() ) { const Trace& halfstream = dynamic_cast<const Trace&>(*(halfstreamIt->second)); output << "\"h\", \"" << halfstream.getStreamKey().toString() << "\""; output << ", " << halfstream.getAttrib("pkt_count"); output << ", " << halfstream.getAttrib("pkt_byte_count"); output << ", " << halfstream.getAttrib("payload_byte_count"); output << ", " << halfstream.getAttrib("nonempty_count"); output << ", " << halfstream.getAttrib("mean_delay"); output << ", " << halfstream.getAttrib("mean_pkt_len"); output << ", " << halfstream.getAttrib("mean_payload_len"); output << ", " << halfstream.getAttrib("mean_nonempty_payload_len"); output << ", " << halfstream.getAttrib("1s_datarate_window.max"); output << ", " << halfstream.getAttrib("5s_datarate_window.max"); output << ", " << halfstream.getAttrib("30s_datarate_window.max"); output << ", " << halfstream.getAttrib("sp_alpha_1"); output << ", " << halfstream.getAttrib("sp_beta_1"); output << ", " << halfstream.getAttrib("sp_gamma_1"); output << ", " << halfstream.getAttrib("sp_delta_1"); output << ", " << halfstream.getAttrib("sp_alpha_2"); output << ", " << halfstream.getAttrib("sp_beta_2"); output << ", " << halfstream.getAttrib("sp_gamma_2"); output << ", " << halfstream.getAttrib("sp_delta_2"); output << ", " << halfstream.getAttrib("sp_alpha_3"); output << ", " << halfstream.getAttrib("sp_beta_3"); output << ", " << halfstream.getAttrib("sp_gamma_3"); output << ", " << halfstream.getAttrib("sp_delta_3"); output << ", " << halfstream.getAttrib("lp_alpha_1"); output << ", " << halfstream.getAttrib("lp_beta_1"); output << ", " << halfstream.getAttrib("lp_gamma_1"); output << ", " << halfstream.getAttrib("lp_alpha_2"); output << ", " << halfstream.getAttrib("lp_beta_2"); output << ", " << halfstream.getAttrib("lp_gamma_2"); output << ", " << halfstream.getAttrib("lp_alpha_3"); output << ", " << halfstream.getAttrib("lp_beta_3"); output << ", " << halfstream.getAttrib("lp_gamma_3"); output << ", " << halfstream.getAttrib("lp_alpha_4"); output << ", " << halfstream.getAttrib("lp_beta_4"); output << ", " << halfstream.getAttrib("lp_gamma_4"); output << ", " << halfstream.getAttrib("lp_alpha_5"); output << ", " << halfstream.getAttrib("lp_beta_5"); output << ", " << halfstream.getAttrib("lp_gamma_5"); output << ", " << halfstream.getAttrib("lp_alpha_6"); output << ", " << halfstream.getAttrib("lp_beta_6"); output << ", " << halfstream.getAttrib("lp_gamma_6"); output << ", " << halfstream.getAttrib("flag_urg"); output << ", " << halfstream.getAttrib("flag_ack"); output << ", " << halfstream.getAttrib("flag_psh"); output << ", " << halfstream.getAttrib("flag_rst"); output << ", " << halfstream.getAttrib("flag_syn"); output << ", " << halfstream.getAttrib("flag_fin"); output << endl; // output per-halfstream attributes if( printout_packets ) { TraceIterator it = halfstream.begin(); while( ! ( it == halfstream.end() ) ) { output << it->getAttrib(pkttime); try { output << "," << it->getAttrib(timeDelta); } catch( UnknownAttributeException unk ) { // expected for first one output << ", 0.000000000"; } catch( ... ) { cerr << "blech" << endl; } output << ", " << it->getAttrib(PacketAttribute("transport.len")); output << endl; ++it; } } ++halfstreamIt; } } uint32_t StatsPrinter::handlePassedStreamEvent( const StreamEvent& e ) { const Decomposition* decomp = dynamic_cast<const Decomposition*>(e.getStream()); if( NULL != decomp ) { printStream( *(decomp) ); } else { return StreamEvent::STREAM_OK; } return StreamEvent::STREAM_ERASE; } int main( int argc, char **argv ) { try { bool profile = true; bool printout_conversations = true; bool printout_packets = false; bool csv_output = true; StatsPrinter printer; struct tms checkpoint; struct tms tms; if( profile ) { times(&checkpoint); cerr << "Profiling started" << endl; } if( argc < 2 ) { usage(); exit(1); } int i = 1; while( ( argc > i ) && ( argv[i][0] == '-' ) ) { switch( argv[i][1] ) { case 'l': printout_packets = true; break; case '\0': usage(); cerr << "Illegal null option" << endl; exit(1); default: usage(); cerr << "Unknown option " << argv[i][1] << endl; exit(1); } i++; } Trace ethTrace(100); Trace ipFragTrace(100); Trace ipTrace(100); // sessions contains streams keyed by ( src addr, dst addr, proto, src port, dst port ) // bidirectionally; these streams are Decompositions of half-streams, keyed by the same keys, // but unidirectional. Decomposition sessions; Clock clock; // ipTrace.addListener(clock); // stream template - attributes and listeners // - this section defines what attributes will be computed for each stream Decomposition *streamTempl = new Decomposition(); initStreamAttributes( *streamTempl, clock ); // half-stream template - attributes and listeners // - this section defines what attributes will be computed for each half-stream Trace *halfstreamTempl = new Trace(2); initHalfstreamAttributes( *halfstreamTempl, clock ); // create a sessionizer for TCP and UDP // - the sessionizer will take responsibility for the templates; we NULL them out here so that // we don't mistakenly try to free them twice IPv4Sessionizer sessionizer( sessions, streamTempl, halfstreamTempl ); streamTempl = NULL; halfstreamTempl = NULL; ipTrace.addListener( sessionizer ); // IPv4Sessionizer implicitly filters down to TCP/UDP // StatsPrinter will print out the stats for a stream and erase it rather than letting it // expire sessions.addStreamListener( printer ); string filename( argv[i] ); QcapAdaptor qcap(filename); if( profile ) { times(&tms); cerr << "Initialization : " << ( tms.tms_utime - checkpoint.tms_utime ) << " user, " << ( tms.tms_stime - checkpoint.tms_stime ) << " sys" << endl; checkpoint = tms; } qcap.getIPTrace( ethTrace, ipFragTrace, ipTrace ); if( profile ) { times(&tms); cerr << "Built IPv4 trace : " << ( tms.tms_utime - checkpoint.tms_utime ) << " user, " << ( tms.tms_stime - checkpoint.tms_stime ) << " sys" << endl; checkpoint = tms; } if( printout_conversations ) { cout << "\"== Expired TCP and UDP Streams ==\"" << endl; vector<Aggregate*>::const_iterator expiredStreamIt = sessions.expiredSubstreamsBegin(); while( expiredStreamIt != sessions.expiredSubstreamsEnd() ) { printer.printStream( dynamic_cast<const Decomposition&>(**expiredStreamIt), csv_output, printout_packets ); ++expiredStreamIt; } cout << "\"== Active TCP and UDP Streams ==\"" << endl; Decomposition::const_iterator activeStreamIt = sessions.activeSubstreamsBegin(); while( activeStreamIt != sessions.activeSubstreamsEnd() ) { printer.printStream( dynamic_cast<const Decomposition&>(*(activeStreamIt->second)), csv_output, printout_packets ); ++activeStreamIt; } if( profile ) { times(&tms); cerr << "Iterated through streams : " << ( tms.tms_utime - checkpoint.tms_utime ) << " user, " << ( tms.tms_stime - checkpoint.tms_stime ) << " sys" << endl; checkpoint = tms; } } } catch( runtime_error err ) { cerr << "Runtime error occurred, message: " << err.what() << endl; } return 0; }