diff --git a/src/analyzer/protocol/dnp3/DNP3.cc b/src/analyzer/protocol/dnp3/DNP3.cc index 3d413a9c1c..f01ddd9503 100644 --- a/src/analyzer/protocol/dnp3/DNP3.cc +++ b/src/analyzer/protocol/dnp3/DNP3.cc @@ -109,21 +109,242 @@ const unsigned int PSEUDO_APP_LAYER_INDEX = 11; // index of first DNP3 app-laye const unsigned int PSEUDO_TRANSPORT_LEN = 1; // length of DNP3 Transport Layer const unsigned int PSEUDO_LINK_LAYER_LEN = 8; // length of DNP3 Pseudo Link Layer -bool DNP3_TCP_Analyzer::crc_table_initialized = false; -unsigned int DNP3_TCP_Analyzer::crc_table[256]; +bool DNP3_Analyzer::crc_table_initialized = false; +unsigned int DNP3_Analyzer::crc_table[256]; -bool DNP3_UDP_Analyzer::crc_table_initialized = false; -unsigned int DNP3_UDP_Analyzer::crc_table[256]; + +DNP3_Analyzer::DNP3_Analyzer() + { + if ( ! crc_table_initialized ) + PrecomputeCRCTable(); + } +DNP3_Analyzer::~DNP3_Analyzer() + { + } + + +bool DNP3_Analyzer::ProcessData(analyzer::Analyzer* thisAnalyzer, binpac::DNP3::DNP3_Conn* thisInterp, int len, const u_char* data, bool orig) + { + Endpoint* endp = orig ? &orig_state : &resp_state; + + while ( len ) + { + if ( endp->in_hdr ) + { + // We're parsing the DNP3 header and link layer, get that in full. + if ( ! AddToBuffer(endp, PSEUDO_APP_LAYER_INDEX, &data, &len) ) + return true; + + // The first two bytes must always be 0x0564. + if( endp->buffer[0] != 0x05 || endp->buffer[1] != 0x64 ) + { + thisAnalyzer->Weird("dnp3_header_lacks_magic"); + return false; + } + + // Make sure header checksum is correct. + if ( ! CheckCRC(thisAnalyzer, PSEUDO_LINK_LAYER_LEN, endp->buffer, endp->buffer + PSEUDO_LINK_LAYER_LEN, "header") ) + { + thisAnalyzer->ProtocolViolation("broken_checksum"); + return false; + } + + // If the checksum works out, we're pretty certainly DNP3. + thisAnalyzer->ProtocolConfirmation(); + + // DNP3 packets without transport and application + // layers can happen, we ignore them. + if ( (endp->buffer[PSEUDO_LENGTH_INDEX] + 3) == (char)PSEUDO_LINK_LAYER_LEN ) + { + //ClearEndpointState(orig); + ClearEndpointState(thisInterp, orig); + return true; + } + + // Double check the direction in case the first + // received packet is a response. + u_char ctrl = endp->buffer[PSEUDO_CONTROL_FIELD_INDEX]; + + if ( orig != (bool)(ctrl & 0x80) ) + thisAnalyzer->Weird("dnp3_unexpected_flow_direction"); + + // Update state. + endp->pkt_length = endp->buffer[PSEUDO_LENGTH_INDEX]; + endp->tpflags = endp->buffer[PSEUDO_TRANSPORT_INDEX]; + endp->in_hdr = false; // Now parsing application layer. + + // For the first packet, we submit the header to + // BinPAC. + if ( ++endp->pkt_cnt == 1 ) + //interp->NewData(orig, endp->buffer, endp->buffer + PSEUDO_LINK_LAYER_LEN); + thisInterp->NewData(orig, endp->buffer, endp->buffer + PSEUDO_LINK_LAYER_LEN); + } + + if ( ! endp->in_hdr ) + { + assert(endp->pkt_length); + + // We're parsing the DNP3 application layer, get that + // in full now as well. We calculate the number of + // raw bytes the application layer consists of from + // the packet length by determining how much 16-byte + // chunks fit in there, and then add 2 bytes CRC for + // each. + int n = PSEUDO_APP_LAYER_INDEX + (endp->pkt_length - 5) + ((endp->pkt_length - 5) / 16) * 2 + + 2 * ( ((endp->pkt_length - 5) % 16 == 0) ? 0 : 1) - 1 ; + + if ( ! AddToBuffer(endp, n, &data, &len) ) + return true; + + // Parse the the application layer data. + //if ( ! ParseAppLayer(endp) ) + if ( ! ParseAppLayer(thisAnalyzer, thisInterp, endp) ) + return false; + + // Done with this packet, prepare for next. + endp->buffer_len = 0; + endp->in_hdr = true; + } + } + + return true; + } + +bool DNP3_Analyzer::AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len) + { + if ( ! target_len ) + return true; + + int to_copy = min(*len, target_len - endp->buffer_len); + + memcpy(endp->buffer + endp->buffer_len, *data, to_copy); + *data += to_copy; + *len -= to_copy; + endp->buffer_len += to_copy; + + return endp->buffer_len == target_len; + } + +bool DNP3_Analyzer::ParseAppLayer(analyzer::Analyzer* thisAnalyzer, binpac::DNP3::DNP3_Conn* thisInterp, Endpoint* endp) + { + bool orig = (endp == &orig_state); + binpac::DNP3::DNP3_Flow* flow = orig ? thisInterp->upflow() : thisInterp->downflow(); + + u_char* data = endp->buffer + PSEUDO_TRANSPORT_INDEX; // The transport layer byte counts as app-layer it seems. + int len = endp->pkt_length - 5; + + // DNP3 Packet : DNP3 Pseudo Link Layer | DNP3 Pseudo Transport Layer | DNP3 Pseudo Application Layer + // DNP3 Serial Transport Layer data is always 1 byte. + // Get FIN FIR seq field in transport header. + // FIR indicate whether the following DNP3 Serial Application Layer is first chunk of bytes or not. + // FIN indicate whether the following DNP3 Serial Application Layer is last chunk of bytes or not. + + int is_first = (endp->tpflags & 0x40) >> 6; // Initial chunk of data in this packet. + int is_last = (endp->tpflags & 0x80) >> 7; // Last chunk of data in this packet. + + int transport = PSEUDO_TRANSPORT_LEN; + + int i = 0; + while ( len > 0 ) + { + int n = min(len, 16); + + // Make sure chunk has a correct checksum. + if ( ! CheckCRC(thisAnalyzer, n, data, data + n, "app_chunk") ) + return false; + + // Pass on to BinPAC. + assert(data + n < endp->buffer + endp->buffer_len); + flow->flow_buffer()->BufferData(data + transport, data + n); + transport = 0; + + data += n + 2; + len -= n; + } + + if ( is_first ) + endp->encountered_first_chunk = true; + + if ( ! is_first && ! endp->encountered_first_chunk ) + { + // We lost the first chunk. + thisAnalyzer->Weird("dnp3_first_application_layer_chunk_missing"); + return false; + } + + if ( is_last ) + { + flow->flow_buffer()->FinishBuffer(); + flow->FlowEOF(); + //ClearEndpointState(orig); + ClearEndpointState(thisInterp, orig); + } + + return true; + } + +void DNP3_Analyzer::ClearEndpointState(binpac::DNP3::DNP3_Conn* thisInterp, bool orig) + { + Endpoint* endp = orig ? &orig_state : &resp_state; + binpac::DNP3::DNP3_Flow* flow = orig ? thisInterp->upflow() : thisInterp->downflow(); //?? + + endp->in_hdr = true; + endp->encountered_first_chunk = false; + endp->buffer_len = 0; + endp->pkt_length = 0; + endp->tpflags = 0; + endp->pkt_cnt = 0; + } + +bool DNP3_Analyzer::CheckCRC(analyzer::Analyzer* thisAnalyzer, int len, const u_char* data, const u_char* crc16, const char* where) + { + unsigned int crc = CalcCRC(len, data); + + if ( crc16[0] == (crc & 0xff) && crc16[1] == (crc & 0xff00) >> 8 ) + return true; + + thisAnalyzer->Weird(fmt("dnp3_corrupt_%s_checksum", where)); + return false; + } + +void DNP3_Analyzer::PrecomputeCRCTable() + { + for( unsigned int i = 0; i < 256; i++) + { + unsigned int crc = i; + + for ( unsigned int j = 0; j < 8; ++j ) + { + if ( crc & 0x0001 ) + crc = (crc >> 1) ^ 0xA6BC; // Generating polynomial. + else + crc >>= 1; + } + + crc_table[i] = crc; + } + } + +unsigned int DNP3_Analyzer::CalcCRC(int len, const u_char* data) + { + unsigned int crc = 0x0000; + + for ( int i = 0; i < len; i++ ) + { + unsigned int index = (crc ^ data[i]) & 0xFF; + crc = crc_table[index] ^ (crc >> 8); + } + + return ~crc & 0xFFFF; + } DNP3_TCP_Analyzer::DNP3_TCP_Analyzer(Connection* c) : TCP_ApplicationAnalyzer("DNP3_TCP", c) { interp = new binpac::DNP3::DNP3_Conn(this); - ClearEndpointState(true); - ClearEndpointState(false); + ClearEndpointState(interp, true); + ClearEndpointState(interp, false); - if ( ! crc_table_initialized ) - PrecomputeCRCTable(); } DNP3_TCP_Analyzer::~DNP3_TCP_Analyzer() @@ -145,7 +366,7 @@ void DNP3_TCP_Analyzer::DeliverStream(int len, const u_char* data, bool orig) try { - if ( ! ProcessData(len, data, orig) ) + if ( ! ProcessData(this, interp, len, data, orig) ) SetSkip(1); } @@ -168,225 +389,13 @@ void DNP3_TCP_Analyzer::EndpointEOF(bool is_orig) interp->FlowEOF(is_orig); } -bool DNP3_TCP_Analyzer::ProcessData(int len, const u_char* data, bool orig) - { - Endpoint* endp = orig ? &orig_state : &resp_state; - - while ( len ) - { - if ( endp->in_hdr ) - { - // We're parsing the DNP3 header and link layer, get that in full. - if ( ! AddToBuffer(endp, PSEUDO_APP_LAYER_INDEX, &data, &len) ) - return true; - - // The first two bytes must always be 0x0564. - if( endp->buffer[0] != 0x05 || endp->buffer[1] != 0x64 ) - { - Weird("dnp3_header_lacks_magic"); - return false; - } - - // Make sure header checksum is correct. - if ( ! CheckCRC(PSEUDO_LINK_LAYER_LEN, endp->buffer, endp->buffer + PSEUDO_LINK_LAYER_LEN, "header") ) - { - ProtocolViolation("broken_checksum"); - return false; - } - - // If the checksum works out, we're pretty certainly DNP3. - ProtocolConfirmation(); - - // DNP3 packets without transport and application - // layers can happen, we ignore them. - if ( (endp->buffer[PSEUDO_LENGTH_INDEX] + 3) == (char)PSEUDO_LINK_LAYER_LEN ) - { - ClearEndpointState(orig); - return true; - } - - // Double check the direction in case the first - // received packet is a response. - u_char ctrl = endp->buffer[PSEUDO_CONTROL_FIELD_INDEX]; - - if ( orig != (bool)(ctrl & 0x80) ) - Weird("dnp3_unexpected_flow_direction"); - - // Update state. - endp->pkt_length = endp->buffer[PSEUDO_LENGTH_INDEX]; - endp->tpflags = endp->buffer[PSEUDO_TRANSPORT_INDEX]; - endp->in_hdr = false; // Now parsing application layer. - - // For the first packet, we submit the header to - // BinPAC. - if ( ++endp->pkt_cnt == 1 ) - interp->NewData(orig, endp->buffer, endp->buffer + PSEUDO_LINK_LAYER_LEN); - } - - if ( ! endp->in_hdr ) - { - assert(endp->pkt_length); - - // We're parsing the DNP3 application layer, get that - // in full now as well. We calculate the number of - // raw bytes the application layer consists of from - // the packet length by determining how much 16-byte - // chunks fit in there, and then add 2 bytes CRC for - // each. - int n = PSEUDO_APP_LAYER_INDEX + (endp->pkt_length - 5) + ((endp->pkt_length - 5) / 16) * 2 + 2 - 1; - - if ( ! AddToBuffer(endp, n, &data, &len) ) - return true; - - // Parse the the application layer data. - if ( ! ParseAppLayer(endp) ) - return false; - - // Done with this packet, prepare for next. - endp->buffer_len = 0; - endp->in_hdr = true; - } - } - - return true; - } - -bool DNP3_TCP_Analyzer::AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len) - { - if ( ! target_len ) - return true; - - int to_copy = min(*len, target_len - endp->buffer_len); - - memcpy(endp->buffer + endp->buffer_len, *data, to_copy); - *data += to_copy; - *len -= to_copy; - endp->buffer_len += to_copy; - - return endp->buffer_len == target_len; - } - -bool DNP3_TCP_Analyzer::ParseAppLayer(Endpoint* endp) - { - bool orig = (endp == &orig_state); - binpac::DNP3::DNP3_Flow* flow = orig ? interp->upflow() : interp->downflow(); - - u_char* data = endp->buffer + PSEUDO_TRANSPORT_INDEX; // The transport layer byte counts as app-layer it seems. - int len = endp->pkt_length - 5; - - // DNP3 Packet : DNP3 Pseudo Link Layer | DNP3 Pseudo Transport Layer | DNP3 Pseudo Application Layer - // DNP3 Serial Transport Layer data is always 1 byte. - // Get FIN FIR seq field in transport header. - // FIR indicate whether the following DNP3 Serial Application Layer is first chunk of bytes or not. - // FIN indicate whether the following DNP3 Serial Application Layer is last chunk of bytes or not. - - int is_first = (endp->tpflags & 0x40) >> 6; // Initial chunk of data in this packet. - int is_last = (endp->tpflags & 0x80) >> 7; // Last chunk of data in this packet. - - int transport = PSEUDO_TRANSPORT_LEN; - - int i = 0; - while ( len > 0 ) - { - int n = min(len, 16); - - // Make sure chunk has a correct checksum. - if ( ! CheckCRC(n, data, data + n, "app_chunk") ) - return false; - - // Pass on to BinPAC. - assert(data + n < endp->buffer + endp->buffer_len); - flow->flow_buffer()->BufferData(data + transport, data + n); - transport = 0; - - data += n + 2; - len -= n; - } - - if ( is_first ) - endp->encountered_first_chunk = true; - - if ( ! is_first && ! endp->encountered_first_chunk ) - { - // We lost the first chunk. - Weird("dnp3_first_application_layer_chunk_missing"); - return false; - } - - if ( is_last ) - { - flow->flow_buffer()->FinishBuffer(); - flow->FlowEOF(); - ClearEndpointState(orig); - } - - return true; - } - -void DNP3_TCP_Analyzer::ClearEndpointState(bool orig) - { - Endpoint* endp = orig ? &orig_state : &resp_state; - binpac::DNP3::DNP3_Flow* flow = orig ? interp->upflow() : interp->downflow(); - - endp->in_hdr = true; - endp->encountered_first_chunk = false; - endp->buffer_len = 0; - endp->pkt_length = 0; - endp->tpflags = 0; - endp->pkt_cnt = 0; - } - -bool DNP3_TCP_Analyzer::CheckCRC(int len, const u_char* data, const u_char* crc16, const char* where) - { - unsigned int crc = CalcCRC(len, data); - - if ( crc16[0] == (crc & 0xff) && crc16[1] == (crc & 0xff00) >> 8 ) - return true; - - Weird(fmt("dnp3_corrupt_%s_checksum", where)); - return false; - } - -void DNP3_TCP_Analyzer::PrecomputeCRCTable() - { - for( unsigned int i = 0; i < 256; i++) - { - unsigned int crc = i; - - for ( unsigned int j = 0; j < 8; ++j ) - { - if ( crc & 0x0001 ) - crc = (crc >> 1) ^ 0xA6BC; // Generating polynomial. - else - crc >>= 1; - } - - crc_table[i] = crc; - } - } - -unsigned int DNP3_TCP_Analyzer::CalcCRC(int len, const u_char* data) - { - unsigned int crc = 0x0000; - - for ( int i = 0; i < len; i++ ) - { - unsigned int index = (crc ^ data[i]) & 0xFF; - crc = crc_table[index] ^ (crc >> 8); - } - - return ~crc & 0xFFFF; - } - -// ?? For DNP3 over UDP analyzer. most of the codes are copied and pasted. Better way to reuse the code? - DNP3_UDP_Analyzer::DNP3_UDP_Analyzer(Connection* c) : Analyzer("DNP3_UDP", c) { interp = new binpac::DNP3::DNP3_Conn(this); - ClearEndpointState(true); - ClearEndpointState(false); + ClearEndpointState(interp, true); + ClearEndpointState(interp, false); if ( ! crc_table_initialized ) PrecomputeCRCTable(); @@ -410,7 +419,7 @@ void DNP3_UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, ui try { - if ( ! ProcessData(len, data, orig) ) + if ( ! ProcessData(this, interp, len, data, orig) ) SetSkip(1); } @@ -420,228 +429,4 @@ void DNP3_UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, ui throw; } } -/* -void DNP3_UDP_Analyzer::Undelivered(uint64 seq, int len, bool orig) - { - Analyzer::Undelivered(seq, len, orig); - interp->NewGap(orig, len); - } -void DNP3_UDP_Analyzer::EndpointEOF(bool is_orig) - { - Analyzer::EndpointEOF(is_orig); - interp->FlowEOF(is_orig); - } -*/ - -bool DNP3_UDP_Analyzer::ProcessData(int len, const u_char* data, bool orig) - { - - Endpoint* endp = orig ? &orig_state : &resp_state; - - - while ( len ) - { - if ( endp->in_hdr ) - { - // We're parsing the DNP3 header and link layer, get that in full. - if ( ! AddToBuffer(endp, PSEUDO_APP_LAYER_INDEX, &data, &len) ) - return true; - - // The first two bytes must always be 0x0564. - if( endp->buffer[0] != 0x05 || endp->buffer[1] != 0x64 ) - { - Weird("dnp3_header_lacks_magic"); - return false; - } - - // Make sure header checksum is correct. - if ( ! CheckCRC(PSEUDO_LINK_LAYER_LEN, endp->buffer, endp->buffer + PSEUDO_LINK_LAYER_LEN, "header") ) - { - ProtocolViolation("broken_checksum"); - return false; - } - - // If the checksum works out, we're pretty certainly DNP3. - ProtocolConfirmation(); - - // DNP3 packets without transport and application - // layers can happen, we ignore them. - if ( (endp->buffer[PSEUDO_LENGTH_INDEX] + 3) == (char)PSEUDO_LINK_LAYER_LEN ) - { - ClearEndpointState(orig); - return true; - } - - // Double check the direction in case the first - // received packet is a response. - u_char ctrl = endp->buffer[PSEUDO_CONTROL_FIELD_INDEX]; - - if ( orig != (bool)(ctrl & 0x80) ) - Weird("dnp3_unexpected_flow_direction"); - - // Update state. - endp->pkt_length = endp->buffer[PSEUDO_LENGTH_INDEX]; - endp->tpflags = endp->buffer[PSEUDO_TRANSPORT_INDEX]; - endp->in_hdr = false; // Now parsing application layer. - - // For the first packet, we submit the header to - // BinPAC. - if ( ++endp->pkt_cnt == 1 ) - interp->NewData(orig, endp->buffer, endp->buffer + PSEUDO_LINK_LAYER_LEN); - } - - if ( ! endp->in_hdr ) - { - assert(endp->pkt_length); - - // We're parsing the DNP3 application layer, get that - // in full now as well. We calculate the number of - // raw bytes the application layer consists of from - // the packet length by determining how much 16-byte - // chunks fit in there, and then add 2 bytes CRC for - // each. - int n = PSEUDO_APP_LAYER_INDEX + (endp->pkt_length - 5) + ((endp->pkt_length - 5) / 16) * 2 + 2 - 1; - - if ( ! AddToBuffer(endp, n, &data, &len) ) - return true; - - // Parse the the application layer data. - if ( ! ParseAppLayer(endp) ) - return false; - - // Done with this packet, prepare for next. - endp->buffer_len = 0; - endp->in_hdr = true; - } - } - - return true; - } - -bool DNP3_UDP_Analyzer::AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len) - { - if ( ! target_len ) - return true; - - int to_copy = min(*len, target_len - endp->buffer_len); - - memcpy(endp->buffer + endp->buffer_len, *data, to_copy); - *data += to_copy; - *len -= to_copy; - endp->buffer_len += to_copy; - - return endp->buffer_len == target_len; - } - -bool DNP3_UDP_Analyzer::ParseAppLayer(Endpoint* endp) - { - bool orig = (endp == &orig_state); - binpac::DNP3::DNP3_Flow* flow = orig ? interp->upflow() : interp->downflow(); - - u_char* data = endp->buffer + PSEUDO_TRANSPORT_INDEX; // The transport layer byte counts as app-layer it seems. - int len = endp->pkt_length - 5; - - // DNP3 Packet : DNP3 Pseudo Link Layer | DNP3 Pseudo Transport Layer | DNP3 Pseudo Application Layer - // DNP3 Serial Transport Layer data is always 1 byte. - // Get FIN FIR seq field in transport header. - // FIR indicate whether the following DNP3 Serial Application Layer is first chunk of bytes or not. - // FIN indicate whether the following DNP3 Serial Application Layer is last chunk of bytes or not. - - int is_first = (endp->tpflags & 0x40) >> 6; // Initial chunk of data in this packet. - int is_last = (endp->tpflags & 0x80) >> 7; // Last chunk of data in this packet. - - int transport = PSEUDO_TRANSPORT_LEN; - - int i = 0; - while ( len > 0 ) - { - int n = min(len, 16); - - // Make sure chunk has a correct checksum. - if ( ! CheckCRC(n, data, data + n, "app_chunk") ) - return false; - - // Pass on to BinPAC. - assert(data + n < endp->buffer + endp->buffer_len); - flow->flow_buffer()->BufferData(data + transport, data + n); - transport = 0; - - data += n + 2; - len -= n; - } - - if ( is_first ) - endp->encountered_first_chunk = true; - - if ( ! is_first && ! endp->encountered_first_chunk ) - { - // We lost the first chunk. - Weird("dnp3_first_application_layer_chunk_missing"); - return false; - } - - if ( is_last ) - { - flow->flow_buffer()->FinishBuffer(); - flow->FlowEOF(); - ClearEndpointState(orig); - } - - return true; - } - -void DNP3_UDP_Analyzer::ClearEndpointState(bool orig) - { - Endpoint* endp = orig ? &orig_state : &resp_state; - binpac::DNP3::DNP3_Flow* flow = orig ? interp->upflow() : interp->downflow(); - - endp->in_hdr = true; - endp->encountered_first_chunk = false; - endp->buffer_len = 0; - endp->pkt_length = 0; - endp->tpflags = 0; - endp->pkt_cnt = 0; - } - -bool DNP3_UDP_Analyzer::CheckCRC(int len, const u_char* data, const u_char* crc16, const char* where) - { - unsigned int crc = CalcCRC(len, data); - - if ( crc16[0] == (crc & 0xff) && crc16[1] == (crc & 0xff00) >> 8 ) - return true; - - Weird(fmt("dnp3_corrupt_%s_checksum", where)); - return false; - } - -void DNP3_UDP_Analyzer::PrecomputeCRCTable() - { - for( unsigned int i = 0; i < 256; i++) - { - unsigned int crc = i; - - for ( unsigned int j = 0; j < 8; ++j ) - { - if ( crc & 0x0001 ) - crc = (crc >> 1) ^ 0xA6BC; // Generating polynomial. - else - crc >>= 1; - } - - crc_table[i] = crc; - } - } - -unsigned int DNP3_UDP_Analyzer::CalcCRC(int len, const u_char* data) - { - unsigned int crc = 0x0000; - - for ( int i = 0; i < len; i++ ) - { - unsigned int index = (crc ^ data[i]) & 0xFF; - crc = crc_table[index] ^ (crc >> 8); - } - - return ~crc & 0xFFFF; - } diff --git a/src/analyzer/protocol/dnp3/DNP3.h b/src/analyzer/protocol/dnp3/DNP3.h index edf8c32e88..e2ac2eb2b1 100644 --- a/src/analyzer/protocol/dnp3/DNP3.h +++ b/src/analyzer/protocol/dnp3/DNP3.h @@ -9,7 +9,44 @@ namespace analyzer { namespace dnp3 { -class DNP3_TCP_Analyzer : public tcp::TCP_ApplicationAnalyzer { + +class DNP3_Analyzer { +public: + DNP3_Analyzer(); + virtual ~DNP3_Analyzer(); + +protected: + static const int MAX_BUFFER_SIZE = 300; + + struct Endpoint { + u_char buffer[MAX_BUFFER_SIZE]; + int buffer_len; + bool in_hdr; + int tpflags; + int pkt_length; + int pkt_cnt; + bool encountered_first_chunk; + }; + + bool ProcessData(analyzer::Analyzer* thisAnalyzer, binpac::DNP3::DNP3_Conn* thisInterp, int len, const u_char* data, bool orig); + void ClearEndpointState(binpac::DNP3::DNP3_Conn* localInterp, bool orig); + bool AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len); + bool ParseAppLayer(analyzer::Analyzer* thisAnalyzer, binpac::DNP3::DNP3_Conn* thisInterp, Endpoint* endp); + bool CheckCRC(analyzer::Analyzer* thisAnalyzer, int len, const u_char* data, const u_char* crc16, const char* where); + unsigned int CalcCRC(int len, const u_char* data); + + static void PrecomputeCRCTable(); + + static bool crc_table_initialized; + static unsigned int crc_table[256]; + + Endpoint orig_state; + Endpoint resp_state; + + +}; + +class DNP3_TCP_Analyzer : public DNP3_Analyzer, public tcp::TCP_ApplicationAnalyzer { public: DNP3_TCP_Analyzer(Connection* conn); virtual ~DNP3_TCP_Analyzer(); @@ -23,38 +60,11 @@ public: { return new DNP3_TCP_Analyzer(conn); } private: - static const int MAX_BUFFER_SIZE = 300; - - struct Endpoint { - u_char buffer[MAX_BUFFER_SIZE]; - int buffer_len; - bool in_hdr; - int tpflags; - int pkt_length; - int pkt_cnt; - bool encountered_first_chunk; - }; - - bool ProcessData(int len, const u_char* data, bool orig); - void ClearEndpointState(bool orig); - bool AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len); - bool ParseAppLayer(Endpoint* endp); - bool CheckCRC(int len, const u_char* data, const u_char* crc16, const char* where); - unsigned int CalcCRC(int len, const u_char* data); - binpac::DNP3::DNP3_Conn* interp; - - Endpoint orig_state; - Endpoint resp_state; - - static void PrecomputeCRCTable(); - - static bool crc_table_initialized; - static unsigned int crc_table[256]; }; -class DNP3_UDP_Analyzer : public analyzer::Analyzer { +class DNP3_UDP_Analyzer : public DNP3_Analyzer, public analyzer::Analyzer { public: DNP3_UDP_Analyzer(Connection* conn); virtual ~DNP3_UDP_Analyzer(); @@ -62,41 +72,12 @@ public: virtual void Done(); virtual void DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen); - //virtual void Undelivered(uint64 seq, int len, bool orig); - //virtual void EndpointEOF(bool is_orig); static analyzer::Analyzer* Instantiate(Connection* conn) { return new DNP3_UDP_Analyzer(conn); } private: - static const int MAX_BUFFER_SIZE = 300; - - struct Endpoint { - u_char buffer[MAX_BUFFER_SIZE]; - int buffer_len; - bool in_hdr; - int tpflags; - int pkt_length; - int pkt_cnt; - bool encountered_first_chunk; - }; - - bool ProcessData(int len, const u_char* data, bool orig); - void ClearEndpointState(bool orig); - bool AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len); - bool ParseAppLayer(Endpoint* endp); - bool CheckCRC(int len, const u_char* data, const u_char* crc16, const char* where); - unsigned int CalcCRC(int len, const u_char* data); - - binpac::DNP3::DNP3_Conn* interp; - - Endpoint orig_state; - Endpoint resp_state; - - static void PrecomputeCRCTable(); - - static bool crc_table_initialized; - static unsigned int crc_table[256]; + binpac::DNP3::DNP3_Conn* interp; };