Merge remote-tracking branch 'origin/dev/2.7'

* origin/dev/2.7:
  Improve introspection of Record and TypeType values
  Bro plugins should support a patch version (x.y.z)
  GH-148: add priority to DNSSEC event handlers
  DNSSEC support in Bro
This commit is contained in:
Jon Siwek 2018-11-29 16:27:38 -06:00
commit 28a2964e38
79 changed files with 1652 additions and 403 deletions

View file

@ -115,6 +115,10 @@ RecordType* dns_answer;
RecordType* dns_soa;
RecordType* dns_edns_additional;
RecordType* dns_tsig_additional;
RecordType* dns_rrsig_rr;
RecordType* dns_dnskey_rr;
RecordType* dns_nsec3_rr;
RecordType* dns_ds_rr;
TableVal* dns_skip_auth;
TableVal* dns_skip_addl;
int dns_skip_all_auth;
@ -430,7 +434,10 @@ void init_net_var()
internal_type("dns_edns_additional")->AsRecordType();
dns_tsig_additional =
internal_type("dns_tsig_additional")->AsRecordType();
dns_rrsig_rr = internal_type("dns_rrsig_rr")->AsRecordType();
dns_dnskey_rr = internal_type("dns_dnskey_rr")->AsRecordType();
dns_nsec3_rr = internal_type("dns_nsec3_rr")->AsRecordType();
dns_ds_rr = internal_type("dns_ds_rr")->AsRecordType();
dns_skip_auth = internal_val("dns_skip_auth")->AsTableVal();
dns_skip_addl = internal_val("dns_skip_addl")->AsTableVal();
dns_skip_all_auth = opt_internal_int("dns_skip_all_auth");

View file

@ -118,6 +118,10 @@ extern RecordType* dns_answer;
extern RecordType* dns_soa;
extern RecordType* dns_edns_additional;
extern RecordType* dns_tsig_additional;
extern RecordType* dns_rrsig_rr;
extern RecordType* dns_dnskey_rr;
extern RecordType* dns_nsec3_rr;
extern RecordType* dns_ds_rr;
extern TableVal* dns_skip_auth;
extern TableVal* dns_skip_addl;
extern int dns_skip_all_auth;

View file

@ -500,6 +500,8 @@ void Val::ValDescribe(ODesc* d) const
AsFunc()->Describe(d);
else if ( type->Tag() == TYPE_FILE )
AsFile()->Describe(d);
else if ( type->Tag() == TYPE_TYPE )
d->Add(type->AsTypeType()->Type()->GetName());
else
d->Add("<no value description>");
break;

View file

@ -312,6 +312,26 @@ int DNS_Interpreter::ParseAnswer(DNS_MsgInfo* msg,
status = ParseRR_TSIG(msg, data, len, rdlength, msg_start);
break;
case TYPE_RRSIG:
status = ParseRR_RRSIG(msg, data, len, rdlength, msg_start);
break;
case TYPE_DNSKEY:
status = ParseRR_DNSKEY(msg, data, len, rdlength, msg_start);
break;
case TYPE_NSEC:
status = ParseRR_NSEC(msg, data, len, rdlength, msg_start);
break;
case TYPE_NSEC3:
status = ParseRR_NSEC3(msg, data, len, rdlength, msg_start);
break;
case TYPE_DS:
status = ParseRR_DS(msg, data, len, rdlength, msg_start);
break;
default:
if ( dns_unknown_reply && ! msg->skip_event )
@ -724,6 +744,17 @@ void DNS_Interpreter::ExtractOctets(const u_char*& data, int& len,
len -= dlen;
}
BroString* DNS_Interpreter::ExtractStream(const u_char*& data, int& len, int l)
{
l = max(l, 0);
int dlen = min(len, l); // Len in bytes of the algorithm use
auto rval = new BroString(data, dlen, 0);
data += dlen;
len -= dlen;
return rval;
}
int DNS_Interpreter::ParseRR_TSIG(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start)
@ -769,6 +800,389 @@ int DNS_Interpreter::ParseRR_TSIG(DNS_MsgInfo* msg,
return 1;
}
int DNS_Interpreter::ParseRR_RRSIG(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start)
{
if ( ! dns_RRSIG || msg->skip_event )
{
data += rdlength;
len -= rdlength;
return 1;
}
if ( len < 18 )
return 0;
unsigned int type_covered = ExtractShort(data, len);
// split the two bytes for algo and labels extraction
uint32 algo_lab = ExtractShort(data, len);
unsigned int algo = (algo_lab >> 8) & 0xff;
unsigned int lab = algo_lab & 0xff;
uint32 orig_ttl = ExtractLong(data, len);
uint32 sign_exp = ExtractLong(data, len);
uint32 sign_incp = ExtractLong(data, len);
unsigned int key_tag = ExtractShort(data, len);
//implement signer's name with the msg_start offset
const u_char* data_start = data;
u_char name[513];
int name_len = sizeof(name) - 1;
u_char* name_end = ExtractName(data, len, name, name_len, msg_start);
if ( ! name_end )
return 0;
int sig_len = rdlength - ((data - data_start) + 18);
DNSSEC_Algo dsa = DNSSEC_Algo(algo);
BroString* sign = ExtractStream(data, len, sig_len);
switch ( dsa ) {
case RSA_MD5:
analyzer->Weird("DNSSEC_RRSIG_NotRecommended_ZoneSignAlgo", fmt("%d", algo));
break;
case Diffie_Hellman:
break;
case DSA_SHA1:
break;
case Elliptic_Curve:
break;
case RSA_SHA1:
break;
case DSA_NSEC3_SHA1:
break;
case RSA_SHA1_NSEC3_SHA1:
break;
case RSA_SHA256:
break;
case RSA_SHA512:
break;
case GOST_R_34_10_2001:
break;
case ECDSA_curveP256withSHA256:
break;
case ECDSA_curveP384withSHA384:
break;
case Indirect:
analyzer->Weird("DNSSEC_RRSIG_Indirect_ZoneSignAlgo", fmt("%d", algo));
break;
case PrivateDNS:
analyzer->Weird("DNSSEC_RRSIG_PrivateDNS_ZoneSignAlgo", fmt("%d", algo));
break;
case PrivateOID:
analyzer->Weird("DNSSEC_RRSIG_PrivateOID_ZoneSignAlgo", fmt("%d", algo));
break;
default:
analyzer->Weird("DNSSEC_RRSIG_unknown_ZoneSignAlgo", fmt("%d", algo));
break;
}
RRSIG_DATA rrsig;
rrsig.type_covered = type_covered;
rrsig.algorithm = algo;
rrsig.labels = lab;
rrsig.orig_ttl = orig_ttl;
rrsig.sig_exp = sign_exp;
rrsig.sig_incep = sign_incp;
rrsig.key_tag = key_tag;
rrsig.signer_name = new BroString(name, name_end - name, 1);
rrsig.signature = sign;
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
vl->append(msg->BuildRRSIG_Val(&rrsig));
analyzer->ConnectionEvent(dns_RRSIG, vl);
return 1;
}
int DNS_Interpreter::ParseRR_DNSKEY(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start)
{
if ( ! dns_DNSKEY || msg->skip_event )
{
data += rdlength;
len -= rdlength;
return 1;
}
if ( len < 4 )
return 0;
auto dflags = ExtractShort(data, len);
// split the two bytes for protocol and algorithm extraction
auto proto_algo = ExtractShort(data, len);
unsigned int dprotocol = (proto_algo >> 8) & 0xff;
unsigned int dalgorithm = proto_algo & 0xff;
DNSSEC_Algo dsa = DNSSEC_Algo(dalgorithm);
//Evaluating the size of remaining bytes for Public Key
BroString* key = ExtractStream(data, len, rdlength - 4);
if ( dflags != 256 and dflags != 257 and dflags != 0 )
analyzer->Weird("DNSSEC_DNSKEY_Invalid_Flag", fmt("%d", dflags));
if ( dprotocol != 3 )
analyzer->Weird("DNSSEC_DNSKEY_Invalid_Protocol", fmt("%d", dprotocol));
switch ( dsa ) {
case RSA_MD5:
analyzer->Weird("DNSSEC_DNSKEY_NotRecommended_ZoneSignAlgo", fmt("%d", dalgorithm));
break;
case Diffie_Hellman:
break;
case DSA_SHA1:
break;
case Elliptic_Curve:
break;
case RSA_SHA1:
break;
case DSA_NSEC3_SHA1:
break;
case RSA_SHA1_NSEC3_SHA1:
break;
case RSA_SHA256:
break;
case RSA_SHA512:
break;
case GOST_R_34_10_2001:
break;
case ECDSA_curveP256withSHA256:
break;
case ECDSA_curveP384withSHA384:
break;
case Indirect:
analyzer->Weird("DNSSEC_DNSKEY_Indirect_ZoneSignAlgo", fmt("%d", dalgorithm));
break;
case PrivateDNS:
analyzer->Weird("DNSSEC_DNSKEY_PrivateDNS_ZoneSignAlgo", fmt("%d", dalgorithm));
break;
case PrivateOID:
analyzer->Weird("DNSSEC_DNSKEY_PrivateOID_ZoneSignAlgo", fmt("%d", dalgorithm));
break;
default:
analyzer->Weird("DNSSEC_DNSKEY_unknown_ZoneSignAlgo", fmt("%d", dalgorithm));
break;
}
DNSKEY_DATA dnskey;
dnskey.dflags = dflags;
dnskey.dalgorithm = dalgorithm;
dnskey.dprotocol = dprotocol;
dnskey.public_key = key;
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
vl->append(msg->BuildDNSKEY_Val(&dnskey));
analyzer->ConnectionEvent(dns_DNSKEY, vl);
return 1;
}
int DNS_Interpreter::ParseRR_NSEC(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start)
{
if ( ! dns_NSEC || msg->skip_event )
{
data += rdlength;
len -= rdlength;
return 1;
}
const u_char* data_start = data;
u_char name[513];
int name_len = sizeof(name) - 1;
u_char* name_end = ExtractName(data, len, name, name_len, msg_start);
if ( ! name_end )
return 0;
int typebitmaps_len = rdlength - (data - data_start);
VectorVal* char_strings = new VectorVal(string_vec);
while ( typebitmaps_len > 0 && len > 0 )
{
uint32 block_bmlen = ExtractShort(data, len);
unsigned int win_blck = (block_bmlen >> 8) & 0xff;
unsigned int bmlen = block_bmlen & 0xff;
if ( bmlen == 0 )
{
analyzer->Weird("DNSSEC_NSEC_bitmapLen0", fmt("%d", win_blck));
break;
}
BroString* bitmap = ExtractStream(data, len, bmlen);
char_strings->Assign(char_strings->Size(), new StringVal(bitmap));
typebitmaps_len = typebitmaps_len - (2 + bmlen);
}
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
vl->append(new StringVal(new BroString(name, name_end - name, 1)));
vl->append(char_strings);
analyzer->ConnectionEvent(dns_NSEC, vl);
return 1;
}
int DNS_Interpreter::ParseRR_NSEC3(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start)
{
if ( ! dns_NSEC3 || msg->skip_event )
{
data += rdlength;
len -= rdlength;
return 1;
}
if ( len < 6 )
return 0;
const u_char* data_start = data;
uint32 halgo_flags = ExtractShort(data, len);
unsigned int hash_algo = (halgo_flags >> 8) & 0xff;
unsigned int nsec_flags = halgo_flags & 0xff;
unsigned int iter = ExtractShort(data, len);
uint8 salt_len = 0;
if ( len > 0 )
{
salt_len = data[0];
++data;
--len;
}
auto salt_val = ExtractStream(data, len, static_cast<int>(salt_len));
uint8 hash_len = 0;
if ( len > 0 )
{
hash_len = data[0];
++data;
--len;
}
auto hash_val = ExtractStream(data, len, static_cast<int>(hash_len));
int typebitmaps_len = rdlength - (data - data_start);
VectorVal* char_strings = new VectorVal(string_vec);
while ( typebitmaps_len > 0 && len > 0 )
{
uint32 block_bmlen = ExtractShort(data, len);
unsigned int win_blck = ( block_bmlen >> 8) & 0xff;
unsigned int bmlen = block_bmlen & 0xff;
if ( bmlen == 0 )
{
analyzer->Weird("DNSSEC_NSEC3_bitmapLen0", fmt("%d", win_blck));
break;
}
BroString* bitmap = ExtractStream(data, len, bmlen);
char_strings->Assign(char_strings->Size(), new StringVal(bitmap));
typebitmaps_len = typebitmaps_len - (2 + bmlen);
}
NSEC3_DATA nsec3;
nsec3.nsec_flags = nsec_flags;
nsec3.nsec_hash_algo = hash_algo;
nsec3.nsec_iter = iter;
nsec3.nsec_salt_len = salt_len;
nsec3.nsec_salt = salt_val;
nsec3.nsec_hlen = hash_len;
nsec3.nsec_hash = hash_val;
nsec3.bitmaps = char_strings;
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
vl->append(msg->BuildNSEC3_Val(&nsec3));
analyzer->ConnectionEvent(dns_NSEC3, vl);
return 1;
}
int DNS_Interpreter::ParseRR_DS(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start)
{
if ( ! dns_DS || msg->skip_event )
{
data += rdlength;
len -= rdlength;
return 1;
}
if ( len < 4 )
return 0;
unsigned int ds_key_tag = ExtractShort(data, len);
// split the two bytes for algorithm and digest type extraction
uint32 ds_algo_dtype = ExtractShort(data, len);
unsigned int ds_algo = (ds_algo_dtype >> 8) & 0xff;
unsigned int ds_dtype = ds_algo_dtype & 0xff;
DNSSEC_Digest ds_digest_type = DNSSEC_Digest(ds_dtype);
BroString* ds_digest = ExtractStream(data, len, rdlength - 4);
switch ( ds_digest_type ) {
case SHA1:
break;
case SHA256:
break;
case GOST_R_34_11_94:
break;
case SHA384:
break;
case reserved0:
analyzer->Weird("DNSSEC_DS_ResrevedDigestType", fmt("%d", ds_dtype));
break;
default:
analyzer->Weird("DNSSEC_DS_unknown_DigestType", fmt("%d", ds_dtype));
break;
}
DS_DATA ds;
ds.key_tag = ds_key_tag;
ds.algorithm = ds_algo;
ds.digest_type = ds_dtype;
ds.digest_val = ds_digest;
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
vl->append(msg->BuildDS_Val(&ds));
analyzer->ConnectionEvent(dns_DS, vl);
return 1;
}
int DNS_Interpreter::ParseRR_A(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength)
{
@ -1063,7 +1477,7 @@ Val* DNS_MsgInfo::BuildEDNS_Val()
// Need to break the TTL field into three components:
// initial: [------------- ttl (32) ---------------------]
// after: [DO][ ext rcode (7)][ver # (8)][ Z field (16)]
// after: [ ext rcode (8)][ver # (8)][ Z field (16) ]
unsigned int ercode = (ttl >> 24) & 0xff;
unsigned int version = (ttl >> 16) & 0xff;
@ -1104,6 +1518,79 @@ Val* DNS_MsgInfo::BuildTSIG_Val()
return r;
}
Val* DNS_MsgInfo::BuildRRSIG_Val(RRSIG_DATA* rrsig)
{
RecordVal* r = new RecordVal(dns_rrsig_rr);
Ref(query_name);
r->Assign(0, query_name);
r->Assign(1, new Val(int(answer_type), TYPE_COUNT));
r->Assign(2, new Val(rrsig->type_covered, TYPE_COUNT));
r->Assign(3, new Val(rrsig->algorithm, TYPE_COUNT));
r->Assign(4, new Val(rrsig->labels, TYPE_COUNT));
r->Assign(5, new IntervalVal(double(rrsig->orig_ttl), Seconds));
r->Assign(6, new Val(double(rrsig->sig_exp), TYPE_TIME));
r->Assign(7, new Val(double(rrsig->sig_incep), TYPE_TIME));
r->Assign(8, new Val(rrsig->key_tag, TYPE_COUNT));
r->Assign(9, new StringVal(rrsig->signer_name));
r->Assign(10, new StringVal(rrsig->signature));
r->Assign(11, new Val(is_query, TYPE_COUNT));
return r;
}
Val* DNS_MsgInfo::BuildDNSKEY_Val(DNSKEY_DATA* dnskey)
{
RecordVal* r = new RecordVal(dns_dnskey_rr);
Ref(query_name);
r->Assign(0, query_name);
r->Assign(1, new Val(int(answer_type), TYPE_COUNT));
r->Assign(2, new Val(dnskey->dflags, TYPE_COUNT));
r->Assign(3, new Val(dnskey->dprotocol, TYPE_COUNT));
r->Assign(4, new Val(dnskey->dalgorithm, TYPE_COUNT));
r->Assign(5, new StringVal(dnskey->public_key));
r->Assign(6, new Val(is_query, TYPE_COUNT));
return r;
}
Val* DNS_MsgInfo::BuildNSEC3_Val(NSEC3_DATA* nsec3)
{
RecordVal* r = new RecordVal(dns_nsec3_rr);
Ref(query_name);
r->Assign(0, query_name);
r->Assign(1, new Val(int(answer_type), TYPE_COUNT));
r->Assign(2, new Val(nsec3->nsec_flags, TYPE_COUNT));
r->Assign(3, new Val(nsec3->nsec_hash_algo, TYPE_COUNT));
r->Assign(4, new Val(nsec3->nsec_iter, TYPE_COUNT));
r->Assign(5, new Val(nsec3->nsec_salt_len, TYPE_COUNT));
r->Assign(6, new StringVal(nsec3->nsec_salt));
r->Assign(7, new Val(nsec3->nsec_hlen, TYPE_COUNT));
r->Assign(8, new StringVal(nsec3->nsec_hash));
r->Assign(9, nsec3->bitmaps);
r->Assign(10, new Val(is_query, TYPE_COUNT));
return r;
}
Val* DNS_MsgInfo::BuildDS_Val(DS_DATA* ds)
{
RecordVal* r = new RecordVal(dns_ds_rr);
Ref(query_name);
r->Assign(0, query_name);
r->Assign(1, new Val(int(answer_type), TYPE_COUNT));
r->Assign(2, new Val(ds->key_tag, TYPE_COUNT));
r->Assign(3, new Val(ds->algorithm, TYPE_COUNT));
r->Assign(4, new Val(ds->digest_type, TYPE_COUNT));
r->Assign(5, new StringVal(ds->digest_val));
r->Assign(6, new Val(is_query, TYPE_COUNT));
return r;
}
Contents_DNS::Contents_DNS(Connection* conn, bool orig,
DNS_Interpreter* arg_interp)
: tcp::TCP_SupportAnalyzer("CONTENTS_DNS", conn, orig)

View file

@ -57,7 +57,12 @@ typedef enum {
TYPE_TKEY = 249, ///< Transaction Key (RFC 2930)
TYPE_TSIG = 250, ///< Transaction Signature (RFC 2845)
TYPE_CAA = 257, ///< Certification Authority Authorization (RFC 6844)
// DNSSEC RR's
TYPE_RRSIG = 46, ///< RR Signature record type (RFC4043)
TYPE_NSEC = 47, ///< Next Secure record (RFC4043)
TYPE_DNSKEY = 48, ///< DNS Key record (RFC 4034)
TYPE_DS = 43, ///< Delegation signer (RFC 4034)
TYPE_NSEC3 = 50,
// The following are only valid in queries.
TYPE_AXFR = 252,
TYPE_ALL = 255,
@ -75,6 +80,33 @@ typedef enum {
DNS_ADDITIONAL,
} DNS_AnswerType;
typedef enum {
reserved0 = 0,
RSA_MD5 = 1, ///< [RFC2537] NOT RECOMMENDED
Diffie_Hellman = 2, ///< [RFC2539]
DSA_SHA1 = 3, ///< [RFC2536] OPTIONAL
Elliptic_Curve = 4,
RSA_SHA1 = 5, ///< [RFC3110] MANDATORY
DSA_NSEC3_SHA1 = 6,
RSA_SHA1_NSEC3_SHA1 = 7,
RSA_SHA256 = 8,
RSA_SHA512 = 10,
GOST_R_34_10_2001 = 12,
ECDSA_curveP256withSHA256 = 13,
ECDSA_curveP384withSHA384 =14,
Indirect = 252, ///<
PrivateDNS = 253, ///< OPTIONAL
PrivateOID = 254, ///< OPTIONAL
reserved255 = 255,
} DNSSEC_Algo;
typedef enum {
reserved = 0,
SHA1 = 1, ///< [RFC3110] MANDATORY
SHA256 = 2,
GOST_R_34_11_94 = 3,
SHA384 = 4,
} DNSSEC_Digest;
struct DNS_RawMsgHdr {
unsigned short id;
@ -105,6 +137,43 @@ struct TSIG_DATA {
unsigned short rr_error;
};
struct RRSIG_DATA {
unsigned short type_covered; // 16 : ExtractShort(data, len)
unsigned short algorithm; // 8
unsigned short labels; // 8
uint32 orig_ttl; // 32
unsigned long sig_exp; // 32
unsigned long sig_incep; // 32
unsigned short key_tag; //16
BroString* signer_name;
BroString* signature;
};
struct DNSKEY_DATA {
unsigned short dflags; // 16 : ExtractShort(data, len)
unsigned short dalgorithm; // 8
unsigned short dprotocol; // 8
BroString* public_key; // Variable lenght Public Key
};
struct NSEC3_DATA {
unsigned short nsec_flags;
unsigned short nsec_hash_algo;
unsigned short nsec_iter;
unsigned short nsec_salt_len;
BroString* nsec_salt;
unsigned short nsec_hlen;
BroString* nsec_hash;
VectorVal* bitmaps;
};
struct DS_DATA {
unsigned short key_tag; // 16 : ExtractShort(data, len)
unsigned short algorithm; // 8
unsigned short digest_type; // 8
BroString* digest_val; // Variable lenght Digest of DNSKEY RR
};
class DNS_MsgInfo {
public:
DNS_MsgInfo(DNS_RawMsgHdr* hdr, int is_query);
@ -114,6 +183,10 @@ public:
Val* BuildAnswerVal();
Val* BuildEDNS_Val();
Val* BuildTSIG_Val();
Val* BuildRRSIG_Val(struct RRSIG_DATA*);
Val* BuildDNSKEY_Val(struct DNSKEY_DATA*);
Val* BuildNSEC3_Val(struct NSEC3_DATA*);
Val* BuildDS_Val(struct DS_DATA*);
int id;
int opcode; ///< query type, see DNS_Opcode
@ -143,8 +216,7 @@ public:
///< for forward lookups
// More values for spesific DNS types.
// struct EDNS_ADDITIONAL* edns;
//struct EDNS_ADDITIONAL* edns;
struct TSIG_DATA* tsig;
};
@ -183,6 +255,8 @@ protected:
uint32 ExtractLong(const u_char*& data, int& len);
void ExtractOctets(const u_char*& data, int& len, BroString** p);
BroString* ExtractStream(const u_char*& data, int& len, int sig_len);
int ParseRR_Name(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
@ -218,7 +292,21 @@ protected:
int ParseRR_TSIG(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_RRSIG(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_DNSKEY(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_NSEC(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_NSEC3(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_DS(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
void SendReplyOrRejectEvent(DNS_MsgInfo* msg, EventHandlerPtr event,
const u_char*& data, int& len,
BroString* question_name);
@ -270,7 +358,6 @@ public:
void Done() override;
void ConnectionClosed(tcp::TCP_Endpoint* endpoint,
tcp::TCP_Endpoint* peer, int gen_event) override;
void ExpireTimer(double t);
static analyzer::Analyzer* Instantiate(Connection* conn)

View file

@ -493,6 +493,73 @@ event dns_EDNS_addl%(c: connection, msg: dns_msg, ans: dns_edns_additional%);
## dns_skip_addl dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_TSIG_addl%(c: connection, msg: dns_msg, ans: dns_tsig_additional%);
## Generated for DNS replies of type *RRSIG*. For replies with multiple answers,
## an individual event of the corresponding type is raised for each.
##
## c: The connection, which may be UDP or TCP depending on the type of the
## transport-layer session being analyzed.
##
## msg: The parsed DNS message header.
##
## ans: The type-independent part of the parsed answer record.
##
## rrsig: The parsed RRSIG record.
event dns_RRSIG%(c: connection, msg: dns_msg, ans: dns_answer, rrsig: dns_rrsig_rr%);
## Generated for DNS replies of type *DNSKEY*. For replies with multiple answers,
## an individual event of the corresponding type is raised for each.
##
## c: The connection, which may be UDP or TCP depending on the type of the
## transport-layer session being analyzed.
##
## msg: The parsed DNS message header.
##
## ans: The type-independent part of the parsed answer record.
##
## dnskey: The parsed DNSKEY record.
event dns_DNSKEY%(c: connection, msg: dns_msg, ans: dns_answer, dnskey: dns_dnskey_rr%);
## Generated for DNS replies of type *NSEC*. For replies with multiple answers,
## an individual event of the corresponding type is raised for each.
##
## c: The connection, which may be UDP or TCP depending on the type of the
## transport-layer session being analyzed.
##
## msg: The parsed DNS message header.
##
## ans: The type-independent part of the parsed answer record.
##
## next_name: The parsed next secure domain name.
##
## bitmaps: vector of strings in hex for the bit maps present.
event dns_NSEC%(c: connection, msg: dns_msg, ans: dns_answer, next_name: string, bitmaps: string_vec%);
## Generated for DNS replies of type *NSEC3*. For replies with multiple answers,
## an individual event of the corresponding type is raised for each.
##
## c: The connection, which may be UDP or TCP depending on the type of the
## transport-layer session being analyzed.
##
## msg: The parsed DNS message header.
##
## ans: The type-independent part of the parsed answer record.
##
## nsec3: The parsed RDATA of Nsec3 record.
event dns_NSEC3%(c: connection, msg: dns_msg, ans: dns_answer, nsec3: dns_nsec3_rr%);
## Generated for DNS replies of type *DS*. For replies with multiple answers,
## an individual event of the corresponding type is raised for each.
##
## c: The connection, which may be UDP or TCP depending on the type of the
## transport-layer session being analyzed.
##
## msg: The parsed DNS message header.
##
## ans: The type-independent part of the parsed answer record.
##
## ds: The parsed RDATA of DS record.
event dns_DS%(c: connection, msg: dns_msg, ans: dns_answer, ds: dns_ds_rr%);
## Generated at the end of processing a DNS packet. This event is the last
## ``dns_*`` event that will be raised for a DNS query/reply and signals that
## all resource records have been passed on.

View file

@ -1896,27 +1896,50 @@ function lookup_ID%(id: string%) : any
## includes the field name, whether it is logged, its value (if it has one),
## and its default value (if specified).
##
## rec: The record to inspect.
## rec: The record value or type to inspect.
##
## Returns: A table that describes the fields of a record.
function record_fields%(rec: any%): record_field_table
%{
TableVal* fields = new TableVal(record_field_table);
RecordVal* rv = rec->AsRecordVal();
RecordType* rt = rv->Type()->AsRecordType();
auto t = rec->Type();
if ( rt->Tag() != TYPE_RECORD )
if ( t->Tag() != TYPE_RECORD && t->Tag() != TYPE_TYPE )
{
reporter->Error("non-record passed to record_fields");
reporter->Error("non-record value/type passed to record_fields");
return fields;
}
RecordType* rt = nullptr;
RecordVal* rv = nullptr;
if ( t->Tag() == TYPE_RECORD )
{
rt = t->AsRecordType();
rv = rec->AsRecordVal();
}
else
{
t = t->AsTypeType()->Type();
if ( t->Tag() != TYPE_RECORD )
{
reporter->Error("non-record value/type passed to record_fields");
return fields;
}
rt = t->AsRecordType();
}
for ( int i = 0; i < rt->NumFields(); ++i )
{
BroType* ft = rt->FieldType(i);
TypeDecl* fd = rt->FieldDecl(i);
Val* fv = rv->Lookup(i);
Val* fv = nullptr;
if ( rv )
fv = rv->Lookup(i);
if ( fv )
Ref(fv);
@ -1924,7 +1947,12 @@ function record_fields%(rec: any%): record_field_table
bool logged = (fd->attrs && fd->FindAttr(ATTR_LOG) != 0);
RecordVal* nr = new RecordVal(record_field);
nr->Assign(0, new StringVal(type_name(rt->Tag())));
if ( ft->Tag() == TYPE_RECORD )
nr->Assign(0, new StringVal("record " + ft->GetName()));
else
nr->Assign(0, new StringVal(type_name(ft->Tag())));
nr->Assign(1, new Val(logged, TYPE_BOOL));
nr->Assign(2, fv);
nr->Assign(3, rt->FieldDefault(i));

View file

@ -445,6 +445,8 @@ void Plugin::Describe(ODesc* d) const
d->Add(config.version.major);
d->Add(".");
d->Add(config.version.minor);
d->Add(".");
d->Add(config.version.patch);
d->Add(")");
}
else

View file

@ -15,7 +15,7 @@
// Increase this when making incompatible changes to the plugin API. Note
// that the constant is never used in C code. It's picked up on by CMake.
#define BRO_PLUGIN_API_VERSION 6
#define BRO_PLUGIN_API_VERSION 7
#define BRO_PLUGIN_BRO_VERSION BRO_VERSION_FUNCTION
@ -67,18 +67,24 @@ extern const char* hook_name(HookType h);
* Helper class to capture a plugin's version.
* */
struct VersionNumber {
int major; //< Major version number;
int minor; //< Minor version number;
int major; //< Major version number.
int minor; //< Minor version number.
int patch; //< Patch version number (available since Bro 2.7).
/**
* Constructor.
*/
VersionNumber() { major = minor = -1; }
VersionNumber() {
// Major and minor versions are required.
major = minor = -1;
// Patch version is optional, and set to 0 if not manually set.
patch = 0;
}
/**
* Returns true if the version is set to a non-negative value.
*/
explicit operator bool() const { return major >= 0 && minor >= 0; }
explicit operator bool() const { return major >= 0 && minor >= 0 && patch >= 0; }
};
/**