diff --git a/AGHTechDoc.md b/AGHTechDoc.md index ee9e7ee8..e5f120d7 100644 --- a/AGHTechDoc.md +++ b/AGHTechDoc.md @@ -1200,6 +1200,7 @@ When a new DNS request is received and processed, we store information about thi "QH":"...", // target host name without the last dot "QT":"...", // question type "QC":"...", // question class + "CP":"" | "doh", // client connection protocol "Answer":"base64 data", "OrigAnswer":"base64 data", "Result":{ @@ -1275,6 +1276,7 @@ Response: "upstream":"...", // Upstream URL starting with tcp://, tls://, https://, or with an IP address "answer_dnssec": true, "client":"127.0.0.1", + "client_proto": "" (plain) | "doh", "elapsedMs":"0.098403", "filterId":1, "question":{ diff --git a/dnsforward/stats.go b/dnsforward/stats.go index e9591abc..3f3ee10c 100644 --- a/dnsforward/stats.go +++ b/dnsforward/stats.go @@ -39,6 +39,11 @@ func processQueryLogsAndStats(ctx *dnsContext) int { Elapsed: elapsed, ClientIP: getIP(d.Addr), } + + if d.HTTPRequest != nil { + p.ClientProto = "doh" + } + if d.Upstream != nil { p.Upstream = d.Upstream.Address() } diff --git a/querylog/decode.go b/querylog/decode.go index 3f381140..fc3f84eb 100644 --- a/querylog/decode.go +++ b/querylog/decode.go @@ -37,6 +37,9 @@ func decodeLogEntry(ent *logEntry, str string) { case "QC": ent.QClass = v + case "CP": + ent.ClientProto = v + case "Answer": ent.Answer, err = base64.StdEncoding.DecodeString(v) case "OrigAnswer": diff --git a/querylog/json.go b/querylog/json.go index cc7e6c39..a1a481f0 100644 --- a/querylog/json.go +++ b/querylog/json.go @@ -63,10 +63,11 @@ func (l *queryLog) logEntryToJSONEntry(entry *logEntry) map[string]interface{} { } jsonEntry := map[string]interface{}{ - "reason": entry.Result.Reason.String(), - "elapsedMs": strconv.FormatFloat(entry.Elapsed.Seconds()*1000, 'f', -1, 64), - "time": entry.Time.Format(time.RFC3339Nano), - "client": l.getClientIP(entry.IP), + "reason": entry.Result.Reason.String(), + "elapsedMs": strconv.FormatFloat(entry.Elapsed.Seconds()*1000, 'f', -1, 64), + "time": entry.Time.Format(time.RFC3339Nano), + "client": l.getClientIP(entry.IP), + "client_proto": entry.ClientProto, } jsonEntry["question"] = map[string]interface{}{ "host": entry.QHost, diff --git a/querylog/qlog.go b/querylog/qlog.go index 27bcc01e..a5780ef1 100644 --- a/querylog/qlog.go +++ b/querylog/qlog.go @@ -38,6 +38,8 @@ type logEntry struct { QType string `json:"QT"` QClass string `json:"QC"` + ClientProto string `json:"CP"` // "" or "doh" + Answer []byte `json:",omitempty"` // sometimes empty answers happen like binerdunt.top or rev2.globalrootservers.net OrigAnswer []byte `json:",omitempty"` @@ -119,9 +121,10 @@ func (l *queryLog) Add(params AddParams) { IP: l.getClientIP(params.ClientIP.String()), Time: now, - Result: *params.Result, - Elapsed: params.Elapsed, - Upstream: params.Upstream, + Result: *params.Result, + Elapsed: params.Elapsed, + Upstream: params.Upstream, + ClientProto: params.ClientProto, } q := params.Question.Question[0] entry.QHost = strings.ToLower(q.Name[:len(q.Name)-1]) // remove the last dot diff --git a/querylog/querylog.go b/querylog/querylog.go index 2fa7ac9d..5431ef1e 100644 --- a/querylog/querylog.go +++ b/querylog/querylog.go @@ -41,13 +41,14 @@ type Config struct { // AddParams - parameters for Add() type AddParams struct { - Question *dns.Msg - Answer *dns.Msg // The response we sent to the client (optional) - OrigAnswer *dns.Msg // The response from an upstream server (optional) - Result *dnsfilter.Result // Filtering result (optional) - Elapsed time.Duration // Time spent for processing the request - ClientIP net.IP - Upstream string + Question *dns.Msg + Answer *dns.Msg // The response we sent to the client (optional) + OrigAnswer *dns.Msg // The response from an upstream server (optional) + Result *dnsfilter.Result // Filtering result (optional) + Elapsed time.Duration // Time spent for processing the request + ClientIP net.IP + Upstream string // Upstream server URL + ClientProto string // Protocol for the client connection: "" (plain), "doh" } // New - create a new instance of the query log