mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
500 lines
15 KiB
JavaScript
500 lines
15 KiB
JavaScript
%extern{
|
|
#include <cstdlib>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
#include "net_util.h"
|
|
#include "util.h"
|
|
%}
|
|
|
|
%header{
|
|
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{
|
|
|
|
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(ntohl(network_order));
|
|
}
|
|
|
|
Val* asn1_obj_to_val(const ASN1Encoding* obj)
|
|
{
|
|
RecordVal* rval = new RecordVal(BifType::Record::SNMP::ObjectValue);
|
|
uint8 tag = obj->meta()->tag();
|
|
|
|
rval->Assign(0, val_mgr->Count(tag));
|
|
|
|
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;
|
|
}
|
|
|
|
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, val_mgr->Count(header->version()));
|
|
|
|
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, val_mgr->Count(flags_byte));
|
|
v3->Assign(3, val_mgr->Bool(flags_byte & 0x01));
|
|
v3->Assign(4, val_mgr->Bool(flags_byte & 0x02));
|
|
v3->Assign(5, val_mgr->Bool(flags_byte & 0x04));
|
|
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.is_orig} )
|
|
bro_analyzer()->ProtocolConfirmation();
|
|
|
|
if ( rec->unknown() )
|
|
return false;
|
|
|
|
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);
|
|
};
|