Use separate DNSRequestContext struct for adding DNS context to connections

This commit is contained in:
Daniel 2021-10-19 10:25:49 +02:00
parent 49767d4c4a
commit b9b33ed2b3
6 changed files with 59 additions and 42 deletions

View file

@ -263,10 +263,10 @@ func UpdateIPsAndCNAMEs(q *resolver.Query, rrCache *resolver.RRCache, conn *netw
// Create new record for this IP. // Create new record for this IP.
record := resolver.ResolvedDomain{ record := resolver.ResolvedDomain{
Domain: q.FQDN, Domain: q.FQDN,
RRCache: rrCache, Resolver: rrCache.Resolver,
Resolver: rrCache.Resolver, DNSRequestContext: rrCache.ToDNSRequestContext(),
Expires: rrCache.Expires, Expires: rrCache.Expires,
} }
// Resolve all CNAMEs in the correct order and add the to the record. // Resolve all CNAMEs in the correct order and add the to the record.

View file

@ -141,6 +141,12 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg)
// Once we decided on the connection we might need to save it to the database, // Once we decided on the connection we might need to save it to the database,
// so we defer that check for now. // so we defer that check for now.
defer func() { defer func() {
// Add metadata to connection.
if rrCache != nil {
conn.DNSContext = rrCache.ToDNSRequestContext()
conn.Resolver = rrCache.Resolver
}
switch conn.Verdict { switch conn.Verdict {
// We immediately save blocked, dropped or failed verdicts so // We immediately save blocked, dropped or failed verdicts so
// they pop up in the UI. // they pop up in the UI.
@ -222,27 +228,19 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg)
} }
} }
// Handle special cases. // Handle special cases.
if rrCache == nil { switch {
case rrCache == nil:
tracer.Warning("nameserver: received successful, but empty reply from resolver") tracer.Warning("nameserver: received successful, but empty reply from resolver")
return reply(nsutil.ServerFailure("internal error: empty reply")) return reply(nsutil.ServerFailure("internal error: empty reply"))
} case rrCache.RCode == dns.RcodeNameError:
// Return now if NXDomain.
// Add dns context and resolver to connection.
conn.DNSContext = rrCache
conn.Resolver = rrCache.Resolver
// Return now if NXDomain.
if rrCache.RCode == dns.RcodeNameError {
return reply(nsutil.NxDomain("no answer found (NXDomain)")) return reply(nsutil.NxDomain("no answer found (NXDomain)"))
} }
// Check with firewall again after resolving.
tracer.Trace("nameserver: deciding on resolved dns") tracer.Trace("nameserver: deciding on resolved dns")
rrCache = firewall.FilterResolvedDNS(ctx, conn, q, rrCache) rrCache = firewall.FilterResolvedDNS(ctx, conn, q, rrCache)
// Add dns context and resolver to connection.
conn.DNSContext = rrCache
conn.Resolver = rrCache.Resolver
// Check again if there is a responder from the firewall. // Check again if there is a responder from the firewall.
if responder, ok := conn.Reason.Context.(nsutil.Responder); ok { if responder, ok := conn.Reason.Context.(nsutil.Responder); ok {
tracer.Infof("nameserver: handing over request for %s to special filter responder: %s", q.ID(), conn.Reason.Msg) tracer.Infof("nameserver: handing over request for %s to special filter responder: %s", q.ID(), conn.Reason.Msg)

View file

@ -145,7 +145,7 @@ type Connection struct { //nolint:maligned // TODO: fix alignment
ProcessContext ProcessContext ProcessContext ProcessContext
// DNSContext holds additional information about the DNS request that was // DNSContext holds additional information about the DNS request that was
// probably used to resolve the IP of this connection. // probably used to resolve the IP of this connection.
DNSContext *resolver.RRCache DNSContext *resolver.DNSRequestContext
// TunnelContext holds additional information about the tunnel that this // TunnelContext holds additional information about the tunnel that this
// connection is using. // connection is using.
TunnelContext interface{} TunnelContext interface{}
@ -333,7 +333,7 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection {
var scope string var scope string
var resolverInfo *resolver.ResolverInfo var resolverInfo *resolver.ResolverInfo
var dnsContext *resolver.RRCache var dnsContext *resolver.DNSRequestContext
if inbound { if inbound {
@ -365,7 +365,7 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection {
scope = lastResolvedDomain.Domain scope = lastResolvedDomain.Domain
entity.Domain = lastResolvedDomain.Domain entity.Domain = lastResolvedDomain.Domain
entity.CNAME = lastResolvedDomain.CNAMEs entity.CNAME = lastResolvedDomain.CNAMEs
dnsContext = lastResolvedDomain.RRCache dnsContext = lastResolvedDomain.DNSRequestContext
resolverInfo = lastResolvedDomain.Resolver resolverInfo = lastResolvedDomain.Resolver
removeOpenDNSRequest(proc.Pid, lastResolvedDomain.Domain) removeOpenDNSRequest(proc.Pid, lastResolvedDomain.Domain)
} }

View file

@ -44,8 +44,8 @@ type ResolvedDomain struct {
// information. // information.
Resolver *ResolverInfo Resolver *ResolverInfo
// RRCache holds the DNS response that was received for this domain. // DNSRequestContext holds the DNS request context.
RRCache *RRCache DNSRequestContext *DNSRequestContext
// Expires holds the timestamp when this entry expires. // Expires holds the timestamp when this entry expires.
// This does not mean that the entry may not be used anymore afterwards, // This does not mean that the entry may not be used anymore afterwards,

39
resolver/rr_context.go Normal file
View file

@ -0,0 +1,39 @@
package resolver
import (
"time"
"github.com/miekg/dns"
)
// DNSRequestContext is a static structure to add information to DNS request connections.
type DNSRequestContext struct {
Domain string
Question string
RCode string
ServedFromCache bool
RequestingNew bool
IsBackup bool
Filtered bool
Modified time.Time
Expires time.Time
}
// ToDNSRequestContext returns a new DNSRequestContext of the RRCache.
func (rrCache *RRCache) ToDNSRequestContext() *DNSRequestContext {
return &DNSRequestContext{
Domain: rrCache.Domain,
Question: rrCache.Question.String(),
RCode: dns.RcodeToString[rrCache.RCode],
ServedFromCache: rrCache.ServedFromCache,
RequestingNew: rrCache.RequestingNew,
IsBackup: rrCache.IsBackup,
Filtered: rrCache.Filtered,
Modified: time.Unix(rrCache.Modified, 0),
Expires: time.Unix(rrCache.Expires, 0),
}
}

View file

@ -2,7 +2,6 @@ package resolver
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"net" "net"
"time" "time"
@ -45,25 +44,6 @@ type RRCache struct {
Modified int64 Modified int64
} }
func (rrCache *RRCache) MarshalJSON() ([]byte, error) {
var record = struct {
RRCache
Question string
RCode string
Modified time.Time
Expires time.Time
}{
RRCache: *rrCache,
Question: rrCache.Question.String(),
RCode: dns.RcodeToString[rrCache.RCode],
Modified: time.Unix(rrCache.Modified, 0),
Expires: time.Unix(rrCache.Expires, 0),
}
return json.Marshal(record)
}
// ID returns the ID of the RRCache consisting of the domain and question type. // ID returns the ID of the RRCache consisting of the domain and question type.
func (rrCache *RRCache) ID() string { func (rrCache *RRCache) ID() string {
return rrCache.Domain + rrCache.Question.String() return rrCache.Domain + rrCache.Question.String()