mirror of
https://github.com/zeek/zeek.git
synced 2025-10-10 02:28:21 +00:00
Merge remote-tracking branch 'origin/topic/jsiwek/snmp'
* origin/topic/jsiwek/snmp: Add memory leak unit test for SNMP. Fix compiler nitpicks from new SNMP code. Add SNMP datagram parsing support. BIT-1142
This commit is contained in:
commit
cf7e25643e
43 changed files with 2374 additions and 7 deletions
|
@ -28,6 +28,7 @@ add_subdirectory(ntp)
|
|||
add_subdirectory(pia)
|
||||
add_subdirectory(pop3)
|
||||
add_subdirectory(rpc)
|
||||
add_subdirectory(snmp)
|
||||
add_subdirectory(smb)
|
||||
add_subdirectory(smtp)
|
||||
add_subdirectory(socks)
|
||||
|
|
11
src/analyzer/protocol/snmp/CMakeLists.txt
Normal file
11
src/analyzer/protocol/snmp/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
include(BroPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
bro_plugin_begin(Bro SNMP)
|
||||
bro_plugin_cc(SNMP.cc Plugin.cc)
|
||||
bro_plugin_bif(types.bif)
|
||||
bro_plugin_bif(events.bif)
|
||||
bro_plugin_pac(snmp.pac snmp-protocol.pac snmp-analyzer.pac)
|
||||
bro_plugin_end()
|
10
src/analyzer/protocol/snmp/Plugin.cc
Normal file
10
src/analyzer/protocol/snmp/Plugin.cc
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
#include "plugin/Plugin.h"
|
||||
#include "SNMP.h"
|
||||
|
||||
BRO_PLUGIN_BEGIN(Bro, SNMP)
|
||||
BRO_PLUGIN_DESCRIPTION("SNMP Analyzer");
|
||||
BRO_PLUGIN_ANALYZER("SNMP", snmp::SNMP_Analyzer);
|
||||
BRO_PLUGIN_BIF_FILE(types);
|
||||
BRO_PLUGIN_BIF_FILE(events);
|
||||
BRO_PLUGIN_END
|
40
src/analyzer/protocol/snmp/SNMP.cc
Normal file
40
src/analyzer/protocol/snmp/SNMP.cc
Normal file
|
@ -0,0 +1,40 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "SNMP.h"
|
||||
#include "Func.h"
|
||||
#include "types.bif.h"
|
||||
#include "events.bif.h"
|
||||
|
||||
using namespace analyzer::snmp;
|
||||
|
||||
SNMP_Analyzer::SNMP_Analyzer(Connection* conn)
|
||||
: Analyzer("SNMP", conn)
|
||||
{
|
||||
interp = new binpac::SNMP::SNMP_Conn(this);
|
||||
}
|
||||
|
||||
SNMP_Analyzer::~SNMP_Analyzer()
|
||||
{
|
||||
delete interp;
|
||||
}
|
||||
|
||||
void SNMP_Analyzer::Done()
|
||||
{
|
||||
Analyzer::Done();
|
||||
Event(udp_session_done);
|
||||
}
|
||||
|
||||
void SNMP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
|
||||
int seq, const IP_Hdr* ip, int caplen)
|
||||
{
|
||||
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
||||
|
||||
try
|
||||
{
|
||||
interp->NewData(orig, data, data + len);
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
ProtocolViolation(e.c_msg());
|
||||
}
|
||||
}
|
31
src/analyzer/protocol/snmp/SNMP.h
Normal file
31
src/analyzer/protocol/snmp/SNMP.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef ANALYZER_PROTOCOL_SNMP_SNMP_H
|
||||
#define ANALYZER_PROTOCOL_SNMP_SNMP_H
|
||||
|
||||
#include "snmp_pac.h"
|
||||
|
||||
namespace analyzer { namespace snmp {
|
||||
|
||||
class SNMP_Analyzer : public analyzer::Analyzer {
|
||||
|
||||
public:
|
||||
|
||||
SNMP_Analyzer(Connection* conn);
|
||||
virtual ~SNMP_Analyzer();
|
||||
|
||||
virtual void Done();
|
||||
virtual void DeliverPacket(int len, const u_char* data, bool orig,
|
||||
int seq, const IP_Hdr* ip, int caplen);
|
||||
|
||||
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new SNMP_Analyzer(conn); }
|
||||
|
||||
protected:
|
||||
|
||||
binpac::SNMP::SNMP_Conn* interp;
|
||||
};
|
||||
|
||||
} } // namespace analyzer::*
|
||||
|
||||
#endif
|
165
src/analyzer/protocol/snmp/events.bif
Normal file
165
src/analyzer/protocol/snmp/events.bif
Normal file
|
@ -0,0 +1,165 @@
|
|||
## An SNMP ``GetRequest-PDU`` message from either :rfc:`1157` or :rfc:`3416`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_get_request%(c: connection, is_orig: bool, header: SNMP::Header,
|
||||
pdu: SNMP::PDU%);
|
||||
|
||||
## An SNMP ``GetNextRequest-PDU`` message from either :rfc:`1157` or
|
||||
## :rfc:`3416`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_get_next_request%(c: connection, is_orig: bool,
|
||||
header: SNMP::Header, pdu: SNMP::PDU%);
|
||||
|
||||
## An SNMP ``GetResponse-PDU`` message from :rfc:`1157` or a
|
||||
## ``Response-PDU`` from :rfc:`3416`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_response%(c: connection, is_orig: bool, header: SNMP::Header,
|
||||
pdu: SNMP::PDU%);
|
||||
|
||||
## An SNMP ``SetRequest-PDU`` message from either :rfc:`1157` or :rfc:`3416`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_set_request%(c: connection, is_orig: bool, header: SNMP::Header,
|
||||
pdu: SNMP::PDU%);
|
||||
|
||||
## An SNMP ``Trap-PDU`` message from :rfc:`1157`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_trap%(c: connection, is_orig: bool, header: SNMP::Header,
|
||||
pdu: SNMP::TrapPDU%);
|
||||
|
||||
## An SNMP ``GetBulkRequest-PDU`` message from :rfc:`3416`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_get_bulk_request%(c: connection, is_orig: bool,
|
||||
header: SNMP::Header, pdu: SNMP::BulkPDU%);
|
||||
|
||||
## An SNMP ``InformRequest-PDU`` message from :rfc:`3416`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_inform_request%(c: connection, is_orig: bool, header: SNMP::Header,
|
||||
pdu: SNMP::PDU%);
|
||||
|
||||
## An SNMP ``SNMPv2-Trap-PDU`` message from :rfc:`1157`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_trapV2%(c: connection, is_orig: bool, header: SNMP::Header,
|
||||
pdu: SNMP::PDU%);
|
||||
|
||||
## An SNMP ``Report-PDU`` message from :rfc:`3416`.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## pdu: An SNMP PDU data structure.
|
||||
event snmp_report%(c: connection, is_orig: bool, header: SNMP::Header,
|
||||
pdu: SNMP::PDU%);
|
||||
|
||||
## An SNMP PDU message of unknown type.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## tag: The tag of the unknown SNMP PDU.
|
||||
event snmp_unknown_pdu%(c: connection, is_orig: bool, header: SNMP::Header,
|
||||
tag: count%);
|
||||
|
||||
## An SNMPv3 ``ScopedPDUData`` of unknown type (neither plaintext or
|
||||
## an encrypted PDU was in the datagram).
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
##
|
||||
## tag: The tag of the unknown SNMP PDU scope.
|
||||
event snmp_unknown_scoped_pdu%(c: connection, is_orig: bool,
|
||||
header: SNMP::Header, tag: count%);
|
||||
|
||||
## An SNMPv3 encrypted PDU message.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## header: SNMP version-dependent data that precedes PDU data in the top-level
|
||||
## SNMP message structure.
|
||||
event snmp_encrypted_pdu%(c: connection, is_orig: bool, header: SNMP::Header%);
|
||||
|
||||
## A datagram with an unknown SNMP version.
|
||||
##
|
||||
## c: The connection overwhich the SNMP datagram is sent.
|
||||
##
|
||||
## is_orig: The endpoint which sent the SNMP datagram.
|
||||
##
|
||||
## version: The value of the unknown SNMP version.
|
||||
event snmp_unknown_header_version%(c: connection, is_orig: bool,
|
||||
version: count%);
|
598
src/analyzer/protocol/snmp/snmp-analyzer.pac
Normal file
598
src/analyzer/protocol/snmp/snmp-analyzer.pac
Normal file
|
@ -0,0 +1,598 @@
|
|||
%extern{
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "net_util.h"
|
||||
#include "util.h"
|
||||
%}
|
||||
|
||||
%header{
|
||||
StringVal* asn1_oid_to_val(const ASN1Encoding* oid);
|
||||
StringVal* asn1_oid_to_val(const ASN1ObjectIdentifier* oid);
|
||||
|
||||
Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t);
|
||||
Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t);
|
||||
|
||||
StringVal* asn1_octet_string_to_val(const ASN1Encoding* s);
|
||||
StringVal* asn1_octet_string_to_val(const ASN1OctetString* s);
|
||||
|
||||
AddrVal* network_address_to_val(const ASN1Encoding* na);
|
||||
AddrVal* network_address_to_val(const NetworkAddress* na);
|
||||
|
||||
Val* asn1_obj_to_val(const ASN1Encoding* obj);
|
||||
|
||||
RecordVal* build_hdr(const Header* header);
|
||||
RecordVal* build_hdrV3(const Header* header);
|
||||
VectorVal* build_bindings(const VarBindList* vbl);
|
||||
RecordVal* build_pdu(const CommonPDU* pdu);
|
||||
RecordVal* build_trap_pdu(const TrapPDU* pdu);
|
||||
RecordVal* build_bulk_pdu(const GetBulkRequestPDU* pdu);
|
||||
%}
|
||||
|
||||
%code{
|
||||
|
||||
StringVal* asn1_oid_to_val(const ASN1ObjectIdentifier* oid)
|
||||
{
|
||||
return asn1_oid_to_val(oid->encoding());
|
||||
}
|
||||
|
||||
StringVal* asn1_oid_to_val(const ASN1Encoding* oid)
|
||||
{
|
||||
vector<uint64> oid_components;
|
||||
vector<vector<uint8> > subidentifiers;
|
||||
vector<uint64> subidentifier_values;
|
||||
vector<uint8> subidentifier;
|
||||
bytestring const& bs = oid->content();
|
||||
|
||||
for ( int i = 0; i < bs.length(); ++i )
|
||||
{
|
||||
if ( bs[i] & 0x80 )
|
||||
subidentifier.push_back(bs[i] & 0x7f);
|
||||
else
|
||||
{
|
||||
subidentifier.push_back(bs[i]);
|
||||
subidentifiers.push_back(subidentifier);
|
||||
subidentifier.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! subidentifier.empty() || subidentifiers.size() < 1 )
|
||||
// Underflow.
|
||||
return new StringVal("");
|
||||
|
||||
for ( size_t i = 0; i < subidentifiers.size(); ++i )
|
||||
{
|
||||
subidentifier = subidentifiers[i];
|
||||
uint64 value = 0;
|
||||
|
||||
for ( size_t j = 0; j < subidentifier.size(); ++j )
|
||||
{
|
||||
uint64 byte = subidentifier[j];
|
||||
value |= byte << (7 * (subidentifier.size() - (j + 1)));
|
||||
}
|
||||
|
||||
subidentifier_values.push_back(value);
|
||||
}
|
||||
|
||||
string rval;
|
||||
|
||||
for ( size_t i = 0; i < subidentifier_values.size(); ++i )
|
||||
{
|
||||
char tmp[32];
|
||||
|
||||
if ( i > 0 )
|
||||
{
|
||||
rval += ".";
|
||||
snprintf(tmp, sizeof(tmp), "%"PRIu64, subidentifier_values[i]);
|
||||
rval += tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::div_t result = std::div(subidentifier_values[i], 40);
|
||||
snprintf(tmp, sizeof(tmp), "%d", result.quot);
|
||||
rval += tmp;
|
||||
rval += ".";
|
||||
snprintf(tmp, sizeof(tmp), "%d", result.rem);
|
||||
rval += tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return new StringVal(rval);
|
||||
}
|
||||
|
||||
Val* asn1_obj_to_val(const ASN1Encoding* obj)
|
||||
{
|
||||
RecordVal* rval = new RecordVal(BifType::Record::SNMP::ObjectValue);
|
||||
uint8 tag = obj->meta()->tag();
|
||||
|
||||
rval->Assign(0, new Val(tag, TYPE_COUNT));
|
||||
|
||||
switch ( tag ) {
|
||||
case VARBIND_UNSPECIFIED_TAG:
|
||||
case VARBIND_NOSUCHOBJECT_TAG:
|
||||
case VARBIND_NOSUCHINSTANCE_TAG:
|
||||
case VARBIND_ENDOFMIBVIEW_TAG:
|
||||
break;
|
||||
|
||||
case ASN1_OBJECT_IDENTIFIER_TAG:
|
||||
rval->Assign(1, asn1_oid_to_val(obj));
|
||||
break;
|
||||
|
||||
case ASN1_INTEGER_TAG:
|
||||
rval->Assign(2, asn1_integer_to_val(obj, TYPE_INT));
|
||||
break;
|
||||
|
||||
case APP_COUNTER32_TAG:
|
||||
case APP_UNSIGNED32_TAG:
|
||||
case APP_TIMETICKS_TAG:
|
||||
case APP_COUNTER64_TAG:
|
||||
rval->Assign(3, asn1_integer_to_val(obj, TYPE_COUNT));
|
||||
break;
|
||||
|
||||
case APP_IPADDRESS_TAG:
|
||||
rval->Assign(4, network_address_to_val(obj));
|
||||
break;
|
||||
|
||||
case ASN1_OCTET_STRING_TAG:
|
||||
case APP_OPAQUE_TAG:
|
||||
default:
|
||||
rval->Assign(5, asn1_octet_string_to_val(obj));
|
||||
break;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
StringVal* asn1_octet_string_to_val(const ASN1OctetString* s)
|
||||
{
|
||||
return asn1_octet_string_to_val(s->encoding());
|
||||
}
|
||||
|
||||
StringVal* asn1_octet_string_to_val(const ASN1Encoding* s)
|
||||
{
|
||||
bytestring const& bs = s->content();
|
||||
return new StringVal(bs.length(), reinterpret_cast<const char*>(bs.data()));
|
||||
}
|
||||
|
||||
Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t)
|
||||
{
|
||||
return asn1_integer_to_val(i->encoding(), t);
|
||||
}
|
||||
|
||||
Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t)
|
||||
{
|
||||
return new Val(binary_to_int64(i->content()), t);
|
||||
}
|
||||
|
||||
AddrVal* network_address_to_val(const NetworkAddress* na)
|
||||
{
|
||||
return network_address_to_val(na->encoding());
|
||||
}
|
||||
|
||||
AddrVal* network_address_to_val(const ASN1Encoding* na)
|
||||
{
|
||||
bytestring const& bs = na->content();
|
||||
|
||||
// IPv6 can probably be presumed to be a octet string of length 16,
|
||||
// but standards don't seem to currently make any provisions for IPv6,
|
||||
// so ignore anything that can't be IPv4.
|
||||
if ( bs.length() != 4 )
|
||||
return new AddrVal(IPAddr());
|
||||
|
||||
const u_char* data = reinterpret_cast<const u_char*>(bs.data());
|
||||
uint32 network_order = extract_uint32(data);
|
||||
return new AddrVal(network_order);
|
||||
}
|
||||
|
||||
Val* time_ticks_to_val(const TimeTicks* tt)
|
||||
{
|
||||
return asn1_integer_to_val(tt->asn1_integer(), TYPE_COUNT);
|
||||
}
|
||||
|
||||
RecordVal* build_hdr(const Header* header)
|
||||
{
|
||||
RecordVal* rv = new RecordVal(BifType::Record::SNMP::Header);
|
||||
rv->Assign(0, new Val(header->version(), TYPE_COUNT));
|
||||
|
||||
switch ( header->version() ) {
|
||||
case SNMPV1_TAG:
|
||||
{
|
||||
RecordVal* v1 = new RecordVal(BifType::Record::SNMP::HeaderV1);
|
||||
v1->Assign(0, asn1_octet_string_to_val(header->v1()->community()));
|
||||
rv->Assign(1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNMPV2_TAG:
|
||||
{
|
||||
RecordVal* v2 = new RecordVal(BifType::Record::SNMP::HeaderV2);
|
||||
v2->Assign(0, asn1_octet_string_to_val(header->v2()->community()));
|
||||
rv->Assign(2, v2);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNMPV3_TAG:
|
||||
{
|
||||
rv->Assign(3, build_hdrV3(header));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
RecordVal* build_hdrV3(const Header* header)
|
||||
{
|
||||
RecordVal* v3 = new RecordVal(BifType::Record::SNMP::HeaderV3);
|
||||
const v3Header* v3hdr = header->v3();
|
||||
const v3HeaderData* global_data = v3hdr->global_data();
|
||||
bytestring const& flags = global_data->flags()->encoding()->content();
|
||||
uint8 flags_byte = flags.length() > 0 ? flags[0] : 0;
|
||||
|
||||
v3->Assign(0, asn1_integer_to_val(global_data->id(), TYPE_COUNT));
|
||||
v3->Assign(1, asn1_integer_to_val(global_data->max_size(),
|
||||
TYPE_COUNT));
|
||||
v3->Assign(2, new Val(flags_byte, TYPE_COUNT));
|
||||
v3->Assign(3, new Val(flags_byte & 0x01, TYPE_BOOL));
|
||||
v3->Assign(4, new Val(flags_byte & 0x02, TYPE_BOOL));
|
||||
v3->Assign(5, new Val(flags_byte & 0x04, TYPE_BOOL));
|
||||
v3->Assign(6, asn1_integer_to_val(global_data->security_model(),
|
||||
TYPE_COUNT));
|
||||
v3->Assign(7, asn1_octet_string_to_val(v3hdr->security_parameters()));
|
||||
|
||||
if ( v3hdr->next()->tag() == ASN1_SEQUENCE_TAG )
|
||||
{
|
||||
const v3ScopedPDU* spdu = v3hdr->plaintext_pdu();
|
||||
RecordVal* rv = new RecordVal(BifType::Record::SNMP::ScopedPDU_Context);
|
||||
rv->Assign(0, asn1_octet_string_to_val(spdu->context_engine_id()));
|
||||
rv->Assign(1, asn1_octet_string_to_val(spdu->context_name()));
|
||||
v3->Assign(8, rv);
|
||||
}
|
||||
|
||||
return v3;
|
||||
}
|
||||
|
||||
VectorVal* build_bindings(const VarBindList* vbl)
|
||||
{
|
||||
VectorVal* vv = new VectorVal(BifType::Vector::SNMP::Bindings);
|
||||
|
||||
for ( size_t i = 0; i < vbl->bindings()->size(); ++i )
|
||||
{
|
||||
VarBind* vb = (*vbl->bindings())[i];
|
||||
RecordVal* binding = new RecordVal(BifType::Record::SNMP::Binding);
|
||||
binding->Assign(0, asn1_oid_to_val(vb->name()->oid()));
|
||||
binding->Assign(1, asn1_obj_to_val(vb->value()->encoding()));
|
||||
vv->Assign(i, binding);
|
||||
}
|
||||
|
||||
return vv;
|
||||
}
|
||||
|
||||
RecordVal* build_pdu(const CommonPDU* pdu)
|
||||
{
|
||||
RecordVal* rv = new RecordVal(BifType::Record::SNMP::PDU);
|
||||
rv->Assign(0, asn1_integer_to_val(pdu->request_id(), TYPE_INT));
|
||||
rv->Assign(1, asn1_integer_to_val(pdu->error_status(), TYPE_INT));
|
||||
rv->Assign(2, asn1_integer_to_val(pdu->error_index(), TYPE_INT));
|
||||
rv->Assign(3, build_bindings(pdu->var_bindings()));
|
||||
return rv;
|
||||
}
|
||||
|
||||
RecordVal* build_trap_pdu(const TrapPDU* pdu)
|
||||
{
|
||||
RecordVal* rv = new RecordVal(BifType::Record::SNMP::TrapPDU);
|
||||
rv->Assign(0, asn1_oid_to_val(pdu->enterprise()));
|
||||
rv->Assign(1, network_address_to_val(pdu->agent_addr()));
|
||||
rv->Assign(2, asn1_integer_to_val(pdu->generic_trap(), TYPE_INT));
|
||||
rv->Assign(3, asn1_integer_to_val(pdu->specific_trap(), TYPE_INT));
|
||||
rv->Assign(4, time_ticks_to_val(pdu->time_stamp()));
|
||||
rv->Assign(5, build_bindings(pdu->var_bindings()));
|
||||
return rv;
|
||||
}
|
||||
|
||||
RecordVal* build_bulk_pdu(const GetBulkRequestPDU* pdu)
|
||||
{
|
||||
RecordVal* rv = new RecordVal(BifType::Record::SNMP::BulkPDU);
|
||||
rv->Assign(0, asn1_integer_to_val(pdu->request_id(), TYPE_INT));
|
||||
rv->Assign(1, asn1_integer_to_val(pdu->non_repeaters(), TYPE_COUNT));
|
||||
rv->Assign(2, asn1_integer_to_val(pdu->max_repititions(), TYPE_COUNT));
|
||||
rv->Assign(3, build_bindings(pdu->var_bindings()));
|
||||
return rv;
|
||||
}
|
||||
%}
|
||||
|
||||
refine connection SNMP_Conn += {
|
||||
|
||||
function proc_get_request(pdu: GetRequestPDU): bool
|
||||
%{
|
||||
if ( ! snmp_get_request )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_get_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_pdu(${pdu.pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_get_next_request(pdu: GetNextRequestPDU): bool
|
||||
%{
|
||||
if ( ! snmp_get_next_request )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_get_next_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_pdu(${pdu.pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_response(pdu: ResponsePDU): bool
|
||||
%{
|
||||
if ( ! snmp_response )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_response(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_pdu(${pdu.pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_set_request(pdu: SetRequestPDU): bool
|
||||
%{
|
||||
if ( ! snmp_set_request )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_set_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_pdu(${pdu.pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_trap(pdu: TrapPDU): bool
|
||||
%{
|
||||
if ( ! snmp_trap )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_trap(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_trap_pdu(${pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_get_bulk_request(pdu: GetBulkRequestPDU): bool
|
||||
%{
|
||||
if ( ! snmp_get_bulk_request )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_get_bulk_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_bulk_pdu(${pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_inform_request(pdu: InformRequestPDU): bool
|
||||
%{
|
||||
if ( ! snmp_inform_request )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_inform_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_pdu(${pdu.pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_v2_trap(pdu: v2TrapPDU): bool
|
||||
%{
|
||||
if ( ! snmp_trapV2 )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_trapV2(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_pdu(${pdu.pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_report(pdu: ReportPDU): bool
|
||||
%{
|
||||
if ( ! snmp_report )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_report(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${pdu.header.is_orig},
|
||||
build_hdr(${pdu.header}),
|
||||
build_pdu(${pdu.pdu}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_unknown_version_header(rec: UnknownVersionHeader): bool
|
||||
%{
|
||||
if ( ! snmp_unknown_header_version )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_unknown_header_version(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${rec.header.is_orig},
|
||||
${rec.header.version});
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_unknown_pdu(rec: UnknownPDU): bool
|
||||
%{
|
||||
if ( ! snmp_unknown_pdu )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_unknown_pdu(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${rec.header.is_orig},
|
||||
build_hdr(${rec.header}),
|
||||
${rec.tag});
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_unknown_scoped_pdu(rec: UnknownScopedPDU): bool
|
||||
%{
|
||||
if ( ! snmp_unknown_scoped_pdu )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_unknown_scoped_pdu(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${rec.header.is_orig},
|
||||
build_hdr(${rec.header}),
|
||||
${rec.tag});
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_encrypted_pdu(rec: EncryptedPDU): bool
|
||||
%{
|
||||
if ( ! snmp_encrypted_pdu )
|
||||
return false;
|
||||
|
||||
BifEvent::generate_snmp_encrypted_pdu(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
${rec.header.is_orig},
|
||||
build_hdr(${rec.header}));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_header(rec: Header): bool
|
||||
%{
|
||||
if ( rec->unknown() )
|
||||
return false;
|
||||
|
||||
bro_analyzer()->ProtocolConfirmation();
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_v3_header_data(rec: v3HeaderData): bool
|
||||
%{
|
||||
if ( rec->flags()->encoding()->content().length() == 1 )
|
||||
return true;
|
||||
|
||||
bro_analyzer()->ProtocolViolation("Invalid v3 HeaderData msgFlags");
|
||||
return false;
|
||||
%}
|
||||
|
||||
function check_tag(rec: ASN1EncodingMeta, expect: uint8): bool
|
||||
%{
|
||||
if ( rec->tag() == expect )
|
||||
return true;
|
||||
|
||||
// Unwind now to stop parsing because it's definitely the
|
||||
// wrong protocol and parsing further could be expensive.
|
||||
// Upper layer of analyzer will catch and call ProtocolViolation().
|
||||
throw binpac::Exception(fmt("Got ASN.1 tag %d, expect %d",
|
||||
rec->tag(), expect));
|
||||
return false;
|
||||
%}
|
||||
|
||||
function check_int_width(rec: ASN1Integer): bool
|
||||
%{
|
||||
int len = rec->encoding()->content().length();
|
||||
|
||||
if ( len <= 9 )
|
||||
// All integers use two's complement form, so an unsigned 64-bit
|
||||
// integer value can require 9 octets to encode if the highest
|
||||
// order bit is set.
|
||||
return true;
|
||||
|
||||
throw binpac::Exception(fmt("ASN.1 integer width overflow: %d", len));
|
||||
return false;
|
||||
%}
|
||||
|
||||
function check_int(rec: ASN1Integer): bool
|
||||
%{
|
||||
return check_tag(rec->encoding()->meta(), ASN1_INTEGER_TAG) &&
|
||||
check_int_width(rec);
|
||||
%}
|
||||
};
|
||||
|
||||
refine typeattr GetRequestPDU += &let {
|
||||
proc: bool = $context.connection.proc_get_request(this);
|
||||
};
|
||||
refine typeattr GetNextRequestPDU += &let {
|
||||
proc: bool = $context.connection.proc_get_next_request(this);
|
||||
};
|
||||
refine typeattr ResponsePDU += &let {
|
||||
proc: bool = $context.connection.proc_response(this);
|
||||
};
|
||||
refine typeattr SetRequestPDU += &let {
|
||||
proc: bool = $context.connection.proc_set_request(this);
|
||||
};
|
||||
refine typeattr TrapPDU += &let {
|
||||
proc: bool = $context.connection.proc_trap(this);
|
||||
};
|
||||
refine typeattr GetBulkRequestPDU += &let {
|
||||
proc: bool = $context.connection.proc_get_bulk_request(this);
|
||||
};
|
||||
refine typeattr InformRequestPDU += &let {
|
||||
proc: bool = $context.connection.proc_inform_request(this);
|
||||
};
|
||||
refine typeattr v2TrapPDU += &let {
|
||||
proc: bool = $context.connection.proc_v2_trap(this);
|
||||
};
|
||||
refine typeattr ReportPDU += &let {
|
||||
proc: bool = $context.connection.proc_report(this);
|
||||
};
|
||||
|
||||
refine typeattr UnknownVersionHeader += &let {
|
||||
proc: bool = $context.connection.proc_unknown_version_header(this);
|
||||
};
|
||||
refine typeattr UnknownPDU += &let {
|
||||
proc: bool = $context.connection.proc_unknown_pdu(this);
|
||||
};
|
||||
refine typeattr UnknownScopedPDU += &let {
|
||||
proc: bool = $context.connection.proc_unknown_scoped_pdu(this);
|
||||
};
|
||||
refine typeattr EncryptedPDU += &let {
|
||||
proc: bool = $context.connection.proc_encrypted_pdu(this);
|
||||
};
|
||||
|
||||
refine typeattr Header += &let {
|
||||
proc: bool = $context.connection.proc_header(this);
|
||||
};
|
||||
|
||||
refine typeattr v3HeaderData += &let {
|
||||
proc: bool = $context.connection.proc_v3_header_data(this);
|
||||
};
|
||||
|
||||
refine typeattr NetworkAddress += &let {
|
||||
valid: bool = $context.connection.check_tag(encoding.meta,
|
||||
APP_IPADDRESS_TAG);
|
||||
};
|
||||
refine typeattr TimeTicks += &let {
|
||||
valid: bool = $context.connection.check_tag(asn1_integer.meta,
|
||||
APP_TIMETICKS_TAG);
|
||||
};
|
||||
|
||||
refine typeattr ASN1SequenceMeta += &let {
|
||||
valid: bool = $context.connection.check_tag(encoding,
|
||||
ASN1_SEQUENCE_TAG);
|
||||
};
|
||||
refine typeattr ASN1Integer += &let {
|
||||
valid: bool = $context.connection.check_int(this);
|
||||
};
|
||||
refine typeattr ASN1OctetString += &let {
|
||||
valid: bool = $context.connection.check_tag(encoding.meta,
|
||||
ASN1_OCTET_STRING_TAG);
|
||||
};
|
||||
refine typeattr ASN1ObjectIdentifier += &let {
|
||||
valid: bool = $context.connection.check_tag(encoding.meta,
|
||||
ASN1_OBJECT_IDENTIFIER_TAG);
|
||||
};
|
272
src/analyzer/protocol/snmp/snmp-protocol.pac
Normal file
272
src/analyzer/protocol/snmp/snmp-protocol.pac
Normal file
|
@ -0,0 +1,272 @@
|
|||
# SNMPv1: RFC 1157
|
||||
# SNMPv2: RFC 1901 and 3416
|
||||
# SNMPv3: RFC 3412
|
||||
# Variable Bindings use definitions from RFC 1155 (and 3416).
|
||||
#
|
||||
# The SNMP protocol uses a well-defined subset of ASN.1 with the
|
||||
# Basic Encoding Rules (BER). Definite-length encodings are always
|
||||
# used. Primitive or non-constructor encodings are preferred over
|
||||
# constructor encodings.
|
||||
|
||||
type TopLevelMessage(is_orig: bool) = record {
|
||||
asn1_sequence_meta: ASN1SequenceMeta;
|
||||
version: ASN1Integer;
|
||||
header: Header(version_value, is_orig);
|
||||
pdu_or_not: case have_plaintext_pdu(header) of {
|
||||
false -> none: empty;
|
||||
true -> pdu: PDU_Choice(header);
|
||||
};
|
||||
} &let {
|
||||
version_value: int64 = binary_to_int64(version.encoding.content);
|
||||
};
|
||||
|
||||
############################## SNMP Header Versions
|
||||
|
||||
enum SNMP_VersionTag {
|
||||
SNMPV1_TAG = 0,
|
||||
SNMPV2_TAG = 1,
|
||||
SNMPV3_TAG = 3,
|
||||
};
|
||||
|
||||
type Header(version: int64, is_orig: bool) = case version of {
|
||||
SNMPV1_TAG -> v1: v1Header(this);
|
||||
SNMPV2_TAG -> v2: v2Header(this);
|
||||
SNMPV3_TAG -> v3: v3Header(this);
|
||||
default -> unknown: UnknownVersionHeader(this);
|
||||
};
|
||||
|
||||
function have_plaintext_pdu(header: Header): bool =
|
||||
case header.version of {
|
||||
SNMPV1_TAG -> true;
|
||||
SNMPV2_TAG -> true;
|
||||
SNMPV3_TAG -> header.v3.next.tag == ASN1_SEQUENCE_TAG;
|
||||
default -> false;
|
||||
};
|
||||
|
||||
type PDU_Choice(header: Header) = record {
|
||||
choice: ASN1EncodingMeta;
|
||||
pdu: PDU(choice.tag, header);
|
||||
};
|
||||
|
||||
type PDU(choice: uint8, header: Header) = case choice of {
|
||||
default -> unknown: UnknownPDU(choice, header);
|
||||
};
|
||||
|
||||
refine casetype PDU += {
|
||||
# PDU choices from RFC 1157.
|
||||
0xa0 -> get_request: GetRequestPDU(header);
|
||||
0xa1 -> get_next_request: GetNextRequestPDU(header);
|
||||
0xa2 -> response: ResponsePDU(header);
|
||||
0xa3 -> set_request: SetRequestPDU(header);
|
||||
0xa4 -> trap: TrapPDU(header);
|
||||
};
|
||||
|
||||
refine casetype PDU += {
|
||||
# PDU choices from RFC 3416.
|
||||
0xa5 -> get_bulk_request: GetBulkRequestPDU(header);
|
||||
0xa6 -> inform_request: InformRequestPDU(header);
|
||||
0xa7 -> v2_trap: v2TrapPDU(header);
|
||||
0xa8 -> report: ReportPDU(header);
|
||||
};
|
||||
|
||||
type v1Header(header: Header) = record {
|
||||
community: ASN1OctetString;
|
||||
};
|
||||
|
||||
type v2Header(header: Header) = record {
|
||||
community: ASN1OctetString;
|
||||
};
|
||||
|
||||
type v3Header(header: Header) = record {
|
||||
global_data: v3HeaderData;
|
||||
security_parameters: ASN1OctetString;
|
||||
next: ASN1EncodingMeta;
|
||||
scoped_pdu_data: case next.tag of {
|
||||
ASN1_SEQUENCE_TAG -> plaintext_pdu: v3ScopedPDU;
|
||||
ASN1_OCTET_STRING_TAG -> encrypted_pdu: EncryptedPDU(header);
|
||||
default -> unknown_pdu: UnknownScopedPDU(next.tag,
|
||||
header);
|
||||
};
|
||||
};
|
||||
|
||||
type v3HeaderData = record {
|
||||
asn1_sequence_meta: ASN1SequenceMeta;
|
||||
id: ASN1Integer;
|
||||
max_size: ASN1Integer;
|
||||
flags: ASN1OctetString;
|
||||
security_model: ASN1Integer;
|
||||
};
|
||||
|
||||
type v3ScopedPDU = record {
|
||||
context_engine_id: ASN1OctetString;
|
||||
context_name: ASN1OctetString;
|
||||
};
|
||||
|
||||
type EncryptedPDU(header: Header) = record {
|
||||
data: bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
type UnknownScopedPDU(tag: uint8, header: Header) = record {
|
||||
data: bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
type UnknownVersionHeader(header: Header) = record {
|
||||
data: bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
############################## SNMP PDUs
|
||||
|
||||
type CommonPDU(header: Header) = record {
|
||||
request_id: ASN1Integer;
|
||||
error_status: ASN1Integer;
|
||||
error_index: ASN1Integer;
|
||||
var_bindings: VarBindList;
|
||||
};
|
||||
|
||||
type GetRequestPDU(header: Header) = record {
|
||||
pdu: CommonPDU(header);
|
||||
};
|
||||
|
||||
type GetNextRequestPDU(header: Header) = record {
|
||||
pdu: CommonPDU(header);
|
||||
};
|
||||
|
||||
type ResponsePDU(header: Header) = record {
|
||||
pdu: CommonPDU(header);
|
||||
};
|
||||
|
||||
type SetRequestPDU(header: Header) = record {
|
||||
pdu: CommonPDU(header);
|
||||
};
|
||||
|
||||
type TrapPDU(header: Header) = record {
|
||||
enterprise: ASN1ObjectIdentifier;
|
||||
agent_addr: NetworkAddress;
|
||||
generic_trap: ASN1Integer;
|
||||
specific_trap: ASN1Integer;
|
||||
time_stamp: TimeTicks;
|
||||
var_bindings: VarBindList;
|
||||
};
|
||||
|
||||
type GetBulkRequestPDU(header: Header) = record {
|
||||
request_id: ASN1Integer;
|
||||
non_repeaters: ASN1Integer;
|
||||
max_repititions: ASN1Integer;
|
||||
var_bindings: VarBindList;
|
||||
};
|
||||
|
||||
type InformRequestPDU(header: Header) = record {
|
||||
pdu: CommonPDU(header);
|
||||
};
|
||||
|
||||
type v2TrapPDU(header: Header) = record {
|
||||
pdu: CommonPDU(header);
|
||||
};
|
||||
|
||||
type ReportPDU(header: Header) = record {
|
||||
pdu: CommonPDU(header);
|
||||
};
|
||||
|
||||
type UnknownPDU(tag: uint8, header: Header) = record {
|
||||
data: bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
type VarBindList = record {
|
||||
asn1_sequence_meta: ASN1SequenceMeta;
|
||||
bindings: VarBind[];
|
||||
};
|
||||
|
||||
type VarBind = record {
|
||||
asn1_sequence_meta: ASN1SequenceMeta;
|
||||
name: ObjectName;
|
||||
value: ObjectSyntax;
|
||||
};
|
||||
|
||||
############################## Variable Binding Encodings (RFC 1155 and 3416)
|
||||
|
||||
type ObjectName = record {
|
||||
oid: ASN1ObjectIdentifier;
|
||||
};
|
||||
|
||||
type ObjectSyntax = record {
|
||||
encoding: ASN1Encoding; # The tag may be a CHOICE among several;
|
||||
};
|
||||
|
||||
type NetworkAddress = record {
|
||||
encoding: ASN1Encoding;
|
||||
};
|
||||
|
||||
type TimeTicks = record {
|
||||
asn1_integer: ASN1Encoding;
|
||||
};
|
||||
|
||||
enum AppSyntaxTypeTag {
|
||||
APP_IPADDRESS_TAG = 0x40,
|
||||
APP_COUNTER32_TAG = 0x41,
|
||||
APP_UNSIGNED32_TAG = 0x42,
|
||||
APP_TIMETICKS_TAG = 0x43,
|
||||
APP_OPAQUE_TAG = 0x44,
|
||||
APP_COUNTER64_TAG = 0x46,
|
||||
};
|
||||
|
||||
enum VarBindNullTag {
|
||||
VARBIND_UNSPECIFIED_TAG = 0x05,
|
||||
VARBIND_NOSUCHOBJECT_TAG = 0x80,
|
||||
VARBIND_NOSUCHINSTANCE_TAG = 0x81,
|
||||
VARBIND_ENDOFMIBVIEW_TAG = 0x82,
|
||||
};
|
||||
|
||||
############################## ASN.1 Encodings
|
||||
|
||||
enum ASN1TypeTag {
|
||||
ASN1_INTEGER_TAG = 0x02,
|
||||
ASN1_OCTET_STRING_TAG = 0x04,
|
||||
ASN1_NULL_TAG = 0x05,
|
||||
ASN1_OBJECT_IDENTIFIER_TAG = 0x06,
|
||||
ASN1_SEQUENCE_TAG = 0x30,
|
||||
};
|
||||
|
||||
type ASN1Encoding = record {
|
||||
meta: ASN1EncodingMeta;
|
||||
content: bytestring &length = meta.length;
|
||||
};
|
||||
|
||||
type ASN1EncodingMeta = record {
|
||||
tag: uint8;
|
||||
len: uint8;
|
||||
more_len: bytestring &length = long_len ? len & 0x7f : 0;
|
||||
} &let {
|
||||
long_len: bool = len & 0x80;
|
||||
length: uint64 = long_len ? binary_to_int64(more_len) : len & 0x7f;
|
||||
};
|
||||
|
||||
type ASN1SequenceMeta = record {
|
||||
encoding: ASN1EncodingMeta;
|
||||
};
|
||||
|
||||
type ASN1Integer = record {
|
||||
encoding: ASN1Encoding;
|
||||
};
|
||||
|
||||
type ASN1OctetString = record {
|
||||
encoding: ASN1Encoding;
|
||||
};
|
||||
|
||||
type ASN1ObjectIdentifier = record {
|
||||
encoding: ASN1Encoding;
|
||||
};
|
||||
|
||||
############################## ASN.1 Conversion Functions
|
||||
|
||||
function binary_to_int64(bs: bytestring): int64
|
||||
%{
|
||||
int64 rval = 0;
|
||||
|
||||
for ( int i = 0; i < bs.length(); ++i )
|
||||
{
|
||||
uint64 byte = bs[i];
|
||||
rval |= byte << (8 * (bs.length() - (i + 1)));
|
||||
}
|
||||
|
||||
return rval;
|
||||
%}
|
25
src/analyzer/protocol/snmp/snmp.pac
Normal file
25
src/analyzer/protocol/snmp/snmp.pac
Normal file
|
@ -0,0 +1,25 @@
|
|||
%include binpac.pac
|
||||
%include bro.pac
|
||||
|
||||
%extern{
|
||||
#include "types.bif.h"
|
||||
#include "events.bif.h"
|
||||
%}
|
||||
|
||||
analyzer SNMP withcontext {
|
||||
connection: SNMP_Conn;
|
||||
flow: SNMP_Flow;
|
||||
};
|
||||
|
||||
connection SNMP_Conn(bro_analyzer: BroAnalyzer) {
|
||||
upflow = SNMP_Flow(true);
|
||||
downflow = SNMP_Flow(false);
|
||||
};
|
||||
|
||||
%include snmp-protocol.pac
|
||||
|
||||
flow SNMP_Flow(is_orig: bool) {
|
||||
datagram = TopLevelMessage(is_orig) withcontext(connection, this);
|
||||
};
|
||||
|
||||
%include snmp-analyzer.pac
|
17
src/analyzer/protocol/snmp/types.bif
Normal file
17
src/analyzer/protocol/snmp/types.bif
Normal file
|
@ -0,0 +1,17 @@
|
|||
module SNMP;
|
||||
|
||||
type Header: record;
|
||||
type HeaderV1: record;
|
||||
type HeaderV2: record;
|
||||
type HeaderV3: record;
|
||||
|
||||
type PDU: record;
|
||||
type TrapPDU: record;
|
||||
type BulkPDU: record;
|
||||
type ScopedPDU_Context: record;
|
||||
|
||||
type ObjectValue: record;
|
||||
type Binding: record;
|
||||
type Bindings: vector;
|
||||
|
||||
module GLOBAL;
|
Loading…
Add table
Add a link
Reference in a new issue