Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DNS header_flags, registered_domain, resolved_ip #13354

Merged
merged 1 commit into from Aug 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.next.asciidoc
Expand Up @@ -333,6 +333,8 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d

*Packetbeat*

- Update DNS protocol plugin to produce events with ECS fields for DNS. {issue}13320[13320] {pull}13354[13354]

*Functionbeat*

- New options to configure roles and VPC. {pull}11779[11779]
Expand Down
69 changes: 56 additions & 13 deletions packetbeat/protos/dns/dns.go
Expand Up @@ -459,6 +459,31 @@ func addDNSToMapStr(m common.MapStr, dns *mkdns.Msg, authority bool, additional
}
m["response_code"] = dnsResponseCodeToString(dns.Rcode)

// Add a list of header flags.
var hf []string
if dns.Authoritative {
hf = append(hf, "AA")
}
if dns.Truncated {
hf = append(hf, "TC")
}
if dns.RecursionDesired {
hf = append(hf, "RD")
}
if dns.RecursionAvailable {
hf = append(hf, "RA")
}
if dns.AuthenticatedData {
hf = append(hf, "AD")
}
if dns.CheckingDisabled {
hf = append(hf, "CD")
}
if opt := dns.IsEdns0(); opt != nil && opt.Do() {
hf = append(hf, "DO")
}
m["header_flags"] = hf

if len(dns.Question) > 0 {
q := dns.Question[0]
qMapStr := common.MapStr{
Expand All @@ -470,7 +495,9 @@ func addDNSToMapStr(m common.MapStr, dns *mkdns.Msg, authority bool, additional

eTLDPlusOne, err := publicsuffix.EffectiveTLDPlusOne(q.Name)
if err == nil {
// etld_plus_one should be removed for 8.0.0.
qMapStr["etld_plus_one"] = eTLDPlusOne
qMapStr["registered_domain"] = eTLDPlusOne
}
}

Expand All @@ -481,12 +508,16 @@ func addDNSToMapStr(m common.MapStr, dns *mkdns.Msg, authority bool, additional

m["answers_count"] = len(dns.Answer)
if len(dns.Answer) > 0 {
m["answers"] = rrsToMapStrs(dns.Answer)
var resolvedIPs []string
m["answers"], resolvedIPs = rrsToMapStrs(dns.Answer, true)
if len(resolvedIPs) > 0 {
m["resolved_ip"] = resolvedIPs
}
}

m["authorities_count"] = len(dns.Ns)
if authority && len(dns.Ns) > 0 {
m["authorities"] = rrsToMapStrs(dns.Ns)
m["authorities"], _ = rrsToMapStrs(dns.Ns, false)
}

if rrOPT != nil {
Expand All @@ -495,7 +526,7 @@ func addDNSToMapStr(m common.MapStr, dns *mkdns.Msg, authority bool, additional
m["additionals_count"] = len(dns.Extra)
}
if additional && len(dns.Extra) > 0 {
rrsMapStrs := rrsToMapStrs(dns.Extra)
rrsMapStrs, _ := rrsToMapStrs(dns.Extra, false)
// We do not want OPT RR to appear in the 'additional' section,
// that's why rrsMapStrs could be empty even though len(dns.Extra) > 0
if len(rrsMapStrs) > 0 {
Expand Down Expand Up @@ -538,23 +569,27 @@ func optToMapStr(rrOPT *mkdns.OPT) common.MapStr {
return optMapStr
}

// rrsToMapStr converts an slice of RR's to an slice of MapStr's.
func rrsToMapStrs(records []mkdns.RR) []common.MapStr {
// rrsToMapStr converts an slice of RR's to an slice of MapStr's and optionally
// returns a list of the IP addresses found in the resource records.
func rrsToMapStrs(records []mkdns.RR, ipList bool) ([]common.MapStr, []string) {
var allIPs []string
mapStrSlice := make([]common.MapStr, 0, len(records))
for _, rr := range records {
rrHeader := rr.Header()

mapStr := rrToMapStr(rr)
mapStr, ips := rrToMapStr(rr, ipList)
if len(mapStr) == 0 { // OPT pseudo-RR returns an empty MapStr
continue
}
allIPs = append(allIPs, ips...)

mapStr["name"] = trimRightDot(rrHeader.Name)
mapStr["type"] = dnsTypeToString(rrHeader.Rrtype)
mapStr["class"] = dnsClassToString(rrHeader.Class)
mapStr["ttl"] = strconv.FormatInt(int64(rrHeader.Ttl), 10)
mapStrSlice = append(mapStrSlice, mapStr)
}
return mapStrSlice
return mapStrSlice, allIPs
}

// Convert all RDATA fields of a RR to a single string
Expand All @@ -566,7 +601,7 @@ func rrToString(rr mkdns.RR) string {
var st string
var keys []string

mapStr := rrToMapStr(rr)
mapStr, _ := rrToMapStr(rr, false)
data, ok := mapStr["data"]
delete(mapStr, "data")

Expand Down Expand Up @@ -599,10 +634,18 @@ func rrToString(rr mkdns.RR) string {
return b.String()
}

func rrToMapStr(rr mkdns.RR) common.MapStr {
func rrToMapStr(rr mkdns.RR, ipList bool) (common.MapStr, []string) {
mapStr := common.MapStr{}
rrType := rr.Header().Rrtype

var ips []string
appendIP := func(ip string) string {
if ipList {
ips = append(ips, ip)
}
return ip
}

switch x := rr.(type) {
default:
// We don't have special handling for this type
Expand All @@ -619,9 +662,9 @@ func rrToMapStr(rr mkdns.RR) common.MapStr {
debugf("Rdata for the unhandled RR type %s could not be fetched", dnsTypeToString(rrType))
}
case *mkdns.A:
mapStr["data"] = x.A.String()
mapStr["data"] = appendIP(x.A.String())
case *mkdns.AAAA:
mapStr["data"] = x.AAAA.String()
mapStr["data"] = appendIP(x.AAAA.String())
case *mkdns.CNAME:
mapStr["data"] = trimRightDot(x.Target)
case *mkdns.DNSKEY:
Expand Down Expand Up @@ -656,7 +699,7 @@ func rrToMapStr(rr mkdns.RR) common.MapStr {
mapStr["data"] = dnsSaltToString(x.Salt)
case *mkdns.OPT: // EDNS [RFC6891]
// OPT pseudo-RR is managed in addDnsToMapStr function
return nil
return nil, nil
case *mkdns.PTR:
mapStr["data"] = trimRightDot(x.Ptr)
case *mkdns.RFC3597:
Expand Down Expand Up @@ -694,7 +737,7 @@ func rrToMapStr(rr mkdns.RR) common.MapStr {
mapStr["data"] = strings.Join(x.Txt, " ")
}

return mapStr
return mapStr, ips
}

// dnsQuestionToString converts a Question to a string.
Expand Down
3 changes: 2 additions & 1 deletion packetbeat/protos/dns/dns_test.go
Expand Up @@ -264,6 +264,7 @@ func assertRequest(t testing.TB, m common.MapStr, q dnsTestMessage) {
assert.Equal(t, q.qType, mapValue(t, m, "dns.question.type"))
assert.Equal(t, q.qName, mapValue(t, m, "dns.question.name"))
assert.Equal(t, q.qEtld, mapValue(t, m, "dns.question.etld_plus_one"))
assert.Equal(t, q.qEtld, mapValue(t, m, "dns.question.registered_domain"))
}

// Assert that the specified flags are set.
Expand Down Expand Up @@ -310,7 +311,7 @@ func TestRRsToMapStrsWithOPTRecord(t *testing.T) {

// The OPT record is a pseudo-record so it doesn't become a real record
// in our conversion, and there will be 1 entry instead of 2.
mapStrs := rrsToMapStrs([]mkdns.RR{o, r})
mapStrs, _ := rrsToMapStrs([]mkdns.RR{o, r}, false)
assert.Len(t, mapStrs, 1)

mapStr := mapStrs[0]
Expand Down