Skip to content

Commit

Permalink
Merge branch 'master' into fix/1726
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtemBaskal committed May 27, 2020
2 parents aebfaf6 + 16a6aad commit 3eac793
Show file tree
Hide file tree
Showing 20 changed files with 1,085 additions and 785 deletions.
4 changes: 3 additions & 1 deletion changelog.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ module.exports = {
],
"scopes": [
"",
"ui",
"global",
"dnsfilter",
"home",
"dnsforward",
"dhcpd",
"documentation"
"querylog",
"documentation",
],
"types": {
"+": {
Expand Down
7 changes: 7 additions & 0 deletions dnsfilter/dnsfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFiltering

// Process rewrites table
// . Find CNAME for a domain name (exact match or by wildcard)
// . if found and CNAME equals to domain name - this is an exception; exit
// . if found, set domain name to canonical name
// . repeat for the new domain name (Note: we return only the last CNAME)
// . Find A or AAAA record for a domain name (exact match or by wildcard)
Expand All @@ -409,6 +410,12 @@ func (d *Dnsfilter) processRewrites(host string) Result {
origHost := host
for len(rr) != 0 && rr[0].Type == dns.TypeCNAME {
log.Debug("Rewrite: CNAME for %s is %s", host, rr[0].Answer)

if host == rr[0].Answer { // "host == CNAME" is an exception
res.Reason = 0
return res
}

host = rr[0].Answer
_, ok := cnames[host]
if ok {
Expand Down
10 changes: 5 additions & 5 deletions dnsfilter/rewrites.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ func (a rewritesArray) Len() int { return len(a) }
func (a rewritesArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

// Priority:
// . CNAME > A/AAAA;
// . exact > wildcard;
// . higher level wildcard > lower level wildcard
// . CNAME < A/AAAA;
// . exact < wildcard;
// . higher level wildcard < lower level wildcard
func (a rewritesArray) Less(i, j int) bool {
if a[i].Type == dns.TypeCNAME && a[j].Type != dns.TypeCNAME {
return false
} else if a[i].Type != dns.TypeCNAME && a[j].Type == dns.TypeCNAME {
return true
} else if a[i].Type != dns.TypeCNAME && a[j].Type == dns.TypeCNAME {
return false
}

if isWildcard(a[i].Domain) {
Expand Down
40 changes: 40 additions & 0 deletions dnsfilter/rewrites_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,43 @@ func TestRewritesLevels(t *testing.T) {
assert.Equal(t, 1, len(r.IPList))
assert.Equal(t, "3.3.3.3", r.IPList[0].String())
}

func TestRewritesException(t *testing.T) {
d := Dnsfilter{}
// wildcard; exception for a sub-domain
d.Rewrites = []RewriteEntry{
RewriteEntry{"*.host.com", "2.2.2.2", 0, nil},
RewriteEntry{"sub.host.com", "sub.host.com", 0, nil},
}
d.prepareRewrites()

// match sub-domain
r := d.processRewrites("my.host.com")
assert.Equal(t, ReasonRewrite, r.Reason)
assert.Equal(t, 1, len(r.IPList))
assert.Equal(t, "2.2.2.2", r.IPList[0].String())

// match sub-domain, but handle exception
r = d.processRewrites("sub.host.com")
assert.Equal(t, NotFilteredNotFound, r.Reason)
}

func TestRewritesExceptionWC(t *testing.T) {
d := Dnsfilter{}
// wildcard; exception for a sub-wildcard
d.Rewrites = []RewriteEntry{
RewriteEntry{"*.host.com", "2.2.2.2", 0, nil},
RewriteEntry{"*.sub.host.com", "*.sub.host.com", 0, nil},
}
d.prepareRewrites()

// match sub-domain
r := d.processRewrites("my.host.com")
assert.Equal(t, ReasonRewrite, r.Reason)
assert.Equal(t, 1, len(r.IPList))
assert.Equal(t, "2.2.2.2", r.IPList[0].String())

// match sub-domain, but handle exception
r = d.processRewrites("my.sub.host.com")
assert.Equal(t, NotFilteredNotFound, r.Reason)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.14
require (
github.com/AdguardTeam/dnsproxy v0.28.1
github.com/AdguardTeam/golibs v0.4.2
github.com/AdguardTeam/urlfilter v0.10.0
github.com/AdguardTeam/urlfilter v0.10.1
github.com/NYTimes/gziphandler v1.1.1
github.com/fsnotify/fsnotify v1.4.7
github.com/gobuffalo/packr v1.30.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKU
github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o=
github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
github.com/AdguardTeam/urlfilter v0.10.0 h1:/YZ4w/UF3KDkL4/QLrQtqalvwBfHHGgrMhk+u3Xm8Mo=
github.com/AdguardTeam/urlfilter v0.10.0/go.mod h1:aMuejlNxpWppOVjiEV87X6z0eMf7wsXHTAIWQuylfZY=
github.com/AdguardTeam/urlfilter v0.10.1 h1:ECago6OvZjOTKlOqxU39C+V/ecAslaCDYcf5s+/hwaY=
github.com/AdguardTeam/urlfilter v0.10.1/go.mod h1:aMuejlNxpWppOVjiEV87X6z0eMf7wsXHTAIWQuylfZY=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
Expand Down
2 changes: 1 addition & 1 deletion home/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

const (
clientsUpdatePeriod = 1 * time.Hour
clientsUpdatePeriod = 10 * time.Minute
)

var webHandlersRegistered = false
Expand Down
7 changes: 7 additions & 0 deletions openapi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# AdGuard Home API Change Log

## v0.103: API changes

### API: Get querylog: GET /control/querylog

* Added optional "offset" and "limit" parameters

We are still using "older_than" approach in AdGuard Home UI, but we realize that it's easier to use offset/limit so here is this option now.

## v0.102: API changes

Expand Down
15 changes: 14 additions & 1 deletion openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,26 @@ paths:
tags:
- log
operationId: queryLog
summary: Get DNS server query log
summary: Get DNS server query log.
parameters:
- name: older_than
in: query
description: Filter by older than
schema:
type: string
- name: offset
in: query
description:
Specify the ranking number of the first item on the page.
Even though it is possible to use "offset" and "older_than",
we recommend choosing one of them and sticking to it.
schema:
type: integer
- name: limit
in: query
description: Limit the number of records to be returned
schema:
type: integer
- name: filter_domain
in: query
description: Filter by domain name
Expand Down
175 changes: 175 additions & 0 deletions querylog/decode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package querylog

import (
"encoding/base64"
"strconv"
"strings"
"time"

"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
)

// decodeLogEntry - decodes query log entry from a line
// nolint (gocyclo)
func decodeLogEntry(ent *logEntry, str string) {
var b bool
var i int
var err error
for {
k, v, t := readJSON(&str)
if t == jsonTErr {
break
}
switch k {
case "IP":
if len(ent.IP) == 0 {
ent.IP = v
}
case "T":
ent.Time, err = time.Parse(time.RFC3339, v)

case "QH":
ent.QHost = v
case "QT":
ent.QType = v
case "QC":
ent.QClass = v

case "Answer":
ent.Answer, err = base64.StdEncoding.DecodeString(v)
case "OrigAnswer":
ent.OrigAnswer, err = base64.StdEncoding.DecodeString(v)

case "IsFiltered":
b, err = strconv.ParseBool(v)
ent.Result.IsFiltered = b
case "Rule":
ent.Result.Rule = v
case "FilterID":
i, err = strconv.Atoi(v)
ent.Result.FilterID = int64(i)
case "Reason":
i, err = strconv.Atoi(v)
ent.Result.Reason = dnsfilter.Reason(i)

case "Upstream":
ent.Upstream = v
case "Elapsed":
i, err = strconv.Atoi(v)
ent.Elapsed = time.Duration(i)

// pre-v0.99.3 compatibility:
case "Question":
var qstr []byte
qstr, err = base64.StdEncoding.DecodeString(v)
if err != nil {
break
}
q := new(dns.Msg)
err = q.Unpack(qstr)
if err != nil {
break
}
ent.QHost = q.Question[0].Name
if len(ent.QHost) == 0 {
break
}
ent.QHost = ent.QHost[:len(ent.QHost)-1]
ent.QType = dns.TypeToString[q.Question[0].Qtype]
ent.QClass = dns.ClassToString[q.Question[0].Qclass]
case "Time":
ent.Time, err = time.Parse(time.RFC3339, v)
}

if err != nil {
log.Debug("decodeLogEntry err: %s", err)
break
}
}
}

// Get value from "key":"value"
func readJSONValue(s, name string) string {
i := strings.Index(s, "\""+name+"\":\"")
if i == -1 {
return ""
}
start := i + 1 + len(name) + 3
i = strings.IndexByte(s[start:], '"')
if i == -1 {
return ""
}
end := start + i
return s[start:end]
}

const (
jsonTErr = iota
jsonTObj
jsonTStr
jsonTNum
jsonTBool
)

// Parse JSON key-value pair
// e.g.: "key":VALUE where VALUE is "string", true|false (boolean), or 123.456 (number)
// Note the limitations:
// . doesn't support whitespace
// . doesn't support "null"
// . doesn't validate boolean or number
// . no proper handling of {} braces
// . no handling of [] brackets
// Return (key, value, type)
func readJSON(ps *string) (string, string, int32) {
s := *ps
k := ""
v := ""
t := int32(jsonTErr)

q1 := strings.IndexByte(s, '"')
if q1 == -1 {
return k, v, t
}
q2 := strings.IndexByte(s[q1+1:], '"')
if q2 == -1 {
return k, v, t
}
k = s[q1+1 : q1+1+q2]
s = s[q1+1+q2+1:]

if len(s) < 2 || s[0] != ':' {
return k, v, t
}

if s[1] == '"' {
q2 = strings.IndexByte(s[2:], '"')
if q2 == -1 {
return k, v, t
}
v = s[2 : 2+q2]
t = jsonTStr
s = s[2+q2+1:]

} else if s[1] == '{' {
t = jsonTObj
s = s[1+1:]

} else {
sep := strings.IndexAny(s[1:], ",}")
if sep == -1 {
return k, v, t
}
v = s[1 : 1+sep]
if s[1] == 't' || s[1] == 'f' {
t = jsonTBool
} else if s[1] == '.' || (s[1] >= '0' && s[1] <= '9') {
t = jsonTNum
}
s = s[1+sep+1:]
}

*ps = s
return k, v, t
}
34 changes: 34 additions & 0 deletions querylog/decode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package querylog

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestJSON(t *testing.T) {
s := `
{"keystr":"val","obj":{"keybool":true,"keyint":123456}}
`
k, v, jtype := readJSON(&s)
assert.Equal(t, jtype, int32(jsonTStr))
assert.Equal(t, "keystr", k)
assert.Equal(t, "val", v)

k, v, jtype = readJSON(&s)
assert.Equal(t, jtype, int32(jsonTObj))
assert.Equal(t, "obj", k)

k, v, jtype = readJSON(&s)
assert.Equal(t, jtype, int32(jsonTBool))
assert.Equal(t, "keybool", k)
assert.Equal(t, "true", v)

k, v, jtype = readJSON(&s)
assert.Equal(t, jtype, int32(jsonTNum))
assert.Equal(t, "keyint", k)
assert.Equal(t, "123456", v)

k, v, jtype = readJSON(&s)
assert.True(t, jtype == jsonTErr)
}
Loading

0 comments on commit 3eac793

Please sign in to comment.