mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
DNS: Implement NAPTR RR support
My phone is sending NAPTR queries and we reported an unknown RR type 35 in weird.log for the response, so figured I'd just add it.
This commit is contained in:
parent
25b5cabab7
commit
4f1fc296b6
11 changed files with 121 additions and 0 deletions
3
NEWS
3
NEWS
|
@ -114,6 +114,9 @@ New Functionality
|
|||
|
||||
redef Intel::manage_seen_event_groups = F;
|
||||
|
||||
- The DNS analyzer was extended to support NAPTR RRs (RFC 2915, RFC 3403).
|
||||
A corresponding ``dns_NAPTR_reply`` event was added.
|
||||
|
||||
Changed Functionality
|
||||
---------------------
|
||||
|
||||
|
|
|
@ -3048,6 +3048,20 @@ type dns_svcb_rr: record {
|
|||
target_name: string; ##< Target name, the hostname of the service endpoint.
|
||||
};
|
||||
|
||||
## A NAPTR record.
|
||||
##
|
||||
## See also RFC 2915 - The Naming Authority Pointer (NAPTR) DNS Resource Record.
|
||||
##
|
||||
## .. zeek:see:: dns_NAPTR_reply
|
||||
type dns_naptr_rr: record {
|
||||
order: count; ##< Order in which to process NAPTR records.
|
||||
preference: count; ##< Preference specifying processing order for *equal* :zeek:field:`dns_naptr_rr$order` fields.
|
||||
flags: string; ##< Flags to control rewriting. E.g. "u", "a", "s" or "p".
|
||||
service: string; ##< The services available down this rewrite path.
|
||||
regexp: string; ##< Substitution expression to be applied to the original query.
|
||||
replacement: string; ##< The next name to query, where the type is depending on the :zeek:field:`dns_naptr_rr$flags` field.
|
||||
};
|
||||
|
||||
# DNS answer types.
|
||||
#
|
||||
# .. zeek:see:: dns_answer
|
||||
|
|
|
@ -537,6 +537,27 @@ event dns_SRV_reply(c: connection, msg: dns_msg, ans: dns_answer, target: string
|
|||
hook DNS::do_reply(c, msg, ans, target);
|
||||
}
|
||||
|
||||
event dns_NAPTR_reply(c: connection, msg: dns_msg, ans: dns_answer, naptr: dns_naptr_rr) &priority=5
|
||||
{
|
||||
# Just encode all the fields for NAPTR RR in the reply string.
|
||||
local tmp = "";
|
||||
|
||||
if ( |naptr$regexp| > 0 )
|
||||
tmp += naptr$regexp;
|
||||
|
||||
if ( |naptr$replacement| > 0 )
|
||||
{
|
||||
if ( |tmp| > 0 )
|
||||
tmp += " ";
|
||||
|
||||
tmp += naptr$replacement;
|
||||
}
|
||||
|
||||
local r = fmt("NAPTR %s %s %s %s %s", naptr$order, naptr$preference, naptr$flags, naptr$service, tmp);
|
||||
|
||||
hook DNS::do_reply(c, msg, ans, r);
|
||||
}
|
||||
|
||||
# TODO: figure out how to handle these
|
||||
#event dns_EDNS(c: connection, msg: dns_msg, ans: dns_answer)
|
||||
# {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "zeek/Event.h"
|
||||
#include "zeek/NetVar.h"
|
||||
#include "zeek/RunState.h"
|
||||
#include "zeek/Val.h"
|
||||
#include "zeek/ZeekString.h"
|
||||
#include "zeek/analyzer/protocol/dns/events.bif.h"
|
||||
#include "zeek/session/Manager.h"
|
||||
|
@ -299,6 +300,8 @@ bool DNS_Interpreter::ParseAnswer(detail::DNS_MsgInfo* msg, const u_char*& data,
|
|||
|
||||
break;
|
||||
|
||||
case detail::TYPE_NAPTR: status = ParseRR_NAPTR(msg, data, len, rdlength, msg_start); break;
|
||||
|
||||
case detail::TYPE_EDNS: status = ParseRR_EDNS(msg, data, len, rdlength, msg_start); break;
|
||||
|
||||
case detail::TYPE_TKEY: status = ParseRR_TKEY(msg, data, len, rdlength, msg_start); break;
|
||||
|
@ -628,6 +631,50 @@ bool DNS_Interpreter::ParseRR_SRV(detail::DNS_MsgInfo* msg, const u_char*& data,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DNS_Interpreter::ParseRR_NAPTR(detail::DNS_MsgInfo* msg, const u_char*& data, int& len, int rdlength,
|
||||
const u_char* msg_start) {
|
||||
zeek_uint_t order = ExtractShort(data, len);
|
||||
zeek_uint_t preference = ExtractShort(data, len);
|
||||
rdlength -= 4;
|
||||
|
||||
if ( len <= 0 || rdlength <= 0 ) {
|
||||
analyzer->AnalyzerViolation("DNS_NAPTR_too_short");
|
||||
return false;
|
||||
}
|
||||
|
||||
// These all check rdlength and return nullptr if there's not enough data available.
|
||||
auto flags = extract_char_string(analyzer, data, len, rdlength);
|
||||
auto service = extract_char_string(analyzer, data, len, rdlength);
|
||||
auto regexp = extract_char_string(analyzer, data, len, rdlength);
|
||||
|
||||
// The replacement string is a name. Compression shouldn't be used, but doesn't seem
|
||||
// we have a helper that would allow to control this.
|
||||
u_char replacement[513];
|
||||
int replacement_len = sizeof(replacement) - 1;
|
||||
u_char* replacement_end = ExtractName(data, len, replacement, replacement_len, msg_start, false);
|
||||
|
||||
if ( ! flags || ! service || ! regexp || ! replacement_end ) {
|
||||
analyzer->AnalyzerViolation("DNS_NAPTR_RR_too_short");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( dns_NAPTR_reply && ! msg->skip_event ) {
|
||||
static auto dns_naptr_rr = id::find_type<RecordType>("dns_naptr_rr");
|
||||
auto r = make_intrusive<RecordVal>(dns_naptr_rr);
|
||||
|
||||
r->Assign(0, order);
|
||||
r->Assign(1, preference);
|
||||
r->Assign(2, std::move(flags));
|
||||
r->Assign(3, std::move(service));
|
||||
r->Assign(4, std::move(regexp));
|
||||
r->Assign(5, zeek::make_intrusive<StringVal>(new String(replacement, replacement_end - replacement, true)));
|
||||
|
||||
analyzer->EnqueueConnEvent(dns_NAPTR_reply, analyzer->ConnVal(), msg->BuildHdrVal(), msg->BuildAnswerVal(), r);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DNS_Interpreter::ParseRR_EDNS(detail::DNS_MsgInfo* msg, const u_char*& data, int& len, int rdlength,
|
||||
const u_char* msg_start) {
|
||||
if ( dns_EDNS_addl && ! msg->skip_event )
|
||||
|
|
|
@ -360,6 +360,7 @@ protected:
|
|||
bool ParseRR_MX(detail::DNS_MsgInfo* msg, const u_char*& data, int& len, int rdlength, const u_char* msg_start);
|
||||
bool ParseRR_NBS(detail::DNS_MsgInfo* msg, const u_char*& data, int& len, int rdlength, const u_char* msg_start);
|
||||
bool ParseRR_SRV(detail::DNS_MsgInfo* msg, const u_char*& data, int& len, int rdlength, const u_char* msg_start);
|
||||
bool ParseRR_NAPTR(detail::DNS_MsgInfo* msg, const u_char*& data, int& len, int rdlength, const u_char* msg_start);
|
||||
bool ParseRR_EDNS(detail::DNS_MsgInfo* msg, const u_char*& data, int& len, int rdlength, const u_char* msg_start);
|
||||
bool ParseRR_EDNS_ECS(detail::DNS_MsgInfo* msg, const u_char*& data, int& len, int rdlength,
|
||||
const u_char* msg_start);
|
||||
|
|
|
@ -467,6 +467,23 @@ event dns_CAA_reply%(c: connection, msg: dns_msg, ans: dns_answer, flags: count,
|
|||
## dns_skip_addl dns_skip_all_addl dns_skip_all_auth dns_skip_auth
|
||||
event dns_SRV_reply%(c: connection, msg: dns_msg, ans: dns_answer, target: string, priority: count, weight: count, p: count%);
|
||||
|
||||
## Generated for DNS replies of type *NAPTR*. 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.
|
||||
##
|
||||
## naptr: The parsed RDATA of NAPTR type record.
|
||||
##
|
||||
## .. zeek:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl
|
||||
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply
|
||||
## dns_TSIG_addl dns_TXT_reply dns_SPF_reply dns_WKS_reply dns_SRV_reply dns_end
|
||||
event dns_NAPTR_reply%(c: connection, msg: dns_msg, ans: dns_answer, naptr: dns_naptr_rr%);
|
||||
|
||||
## Generated on DNS reply resource records when the type of record is not one
|
||||
## that Zeek knows how to parse and generate another more specific event.
|
||||
##
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
NAPTR, [id=20970, opcode=0, rcode=0, QR=T, AA=F, TC=F, RD=T, RA=T, Z=0, AD=F, CD=F, num_queries=1, num_answers=1, num_auth=0, num_addl=0], [answer_type=1, query=fp-de-carrier-vodafone.rcs.telephony.goog, qtype=35, qclass=1, TTL=2.0 mins 48.0 secs], [order=100, preference=100, flags=s, service=SIPS+D2T, regexp=, replacement=_sips._tcp.fp-de-carrier-vodafone.rcs.telephony.goog]
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
uid query qclass_name qtype_name answers
|
||||
CHhAvVGS1DHFjwGM9 fp-de-carrier-vodafone.rcs.telephony.goog C_INTERNET NAPTR NAPTR 100 100 s SIPS+D2T _sips._tcp.fp-de-carrier-vodafone.rcs.telephony.goog
|
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
NAPTR, [id=20970, opcode=0, rcode=0, QR=T, AA=F, TC=F, RD=T, RA=T, Z=0, AD=F, CD=F, num_queries=1, num_answers=1, num_auth=0, num_addl=0], [answer_type=1, query=fp-de-carrier-vodafone.rcs.telephony.goog, qtype=35, qclass=1, TTL=2.0 mins 48.0 secs], [order=100, preference=100, flags=s, service=SIPS+D2T, regexp=, replacement=_sips._tcp.fp-de-carrier-vodafone.rcs.telephony.goog]
|
BIN
testing/btest/Traces/dns/naptr.pcap
Normal file
BIN
testing/btest/Traces/dns/naptr.pcap
Normal file
Binary file not shown.
11
testing/btest/scripts/base/protocols/dns/naptr.zeek
Normal file
11
testing/btest/scripts/base/protocols/dns/naptr.zeek
Normal file
|
@ -0,0 +1,11 @@
|
|||
# @TEST-EXEC: zeek -b -r $TRACES/dns/naptr.pcap %INPUT >out
|
||||
# @TEST-EXEC: btest-diff out
|
||||
# @TEST-EXEC: zeek-cut -m uid query qclass_name qtype_name answers < dns.log > dns.log.cut
|
||||
# @TEST-EXEC: btest-diff dns.log.cut
|
||||
|
||||
@load base/protocols/dns
|
||||
|
||||
event dns_NAPTR_reply(c: connection, msg: dns_msg, ans: dns_answer, naptr: dns_naptr_rr)
|
||||
{
|
||||
print "NAPTR", msg, ans, naptr;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue