all: sync with master; upd chlog

This commit is contained in:
Ainar Garipov
2023-09-07 17:13:48 +03:00
parent 3be7676970
commit 7b93f5d7cf
306 changed files with 19770 additions and 4916 deletions

View File

@@ -2,7 +2,6 @@
package aghhttp
import (
"encoding/json"
"fmt"
"io"
"net/http"
@@ -61,23 +60,3 @@ func WriteTextPlainDeprecated(w http.ResponseWriter, r *http.Request) (isPlainTe
return true
}
// WriteJSONResponse sets the content-type header in w.Header() to
// "application/json", writes a header with a "200 OK" status, encodes resp to
// w, calls [Error] on any returned error, and returns it as well.
func WriteJSONResponse(w http.ResponseWriter, r *http.Request, resp any) (err error) {
return WriteJSONResponseCode(w, r, http.StatusOK, resp)
}
// WriteJSONResponseCode is like [WriteJSONResponse] but adds the ability to
// redefine the status code.
func WriteJSONResponseCode(w http.ResponseWriter, r *http.Request, code int, resp any) (err error) {
w.Header().Set(httphdr.ContentType, HdrValApplicationJSON)
w.WriteHeader(code)
err = json.NewEncoder(w).Encode(resp)
if err != nil {
Error(r, w, http.StatusInternalServerError, "encoding resp: %s", err)
}
return err
}

View File

@@ -4,6 +4,7 @@ package aghhttp
// HTTP header value constants.
const (
HdrValApplicationJSON = "application/json"
HdrValTextPlain = "text/plain"
HdrValApplicationJSON = "application/json"
HdrValStrictTransportSecurity = "max-age=31536000; includeSubDomains"
HdrValTextPlain = "text/plain"
)

142
internal/aghhttp/json.go Normal file
View File

@@ -0,0 +1,142 @@
package aghhttp
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/log"
)
// JSON Utilities
// nsecPerMsec is the number of nanoseconds in a millisecond.
const nsecPerMsec = float64(time.Millisecond / time.Nanosecond)
// JSONDuration is a time.Duration that can be decoded from JSON and encoded
// into JSON according to our API conventions.
type JSONDuration time.Duration
// type check
var _ json.Marshaler = JSONDuration(0)
// MarshalJSON implements the json.Marshaler interface for JSONDuration. err is
// always nil.
func (d JSONDuration) MarshalJSON() (b []byte, err error) {
msec := float64(time.Duration(d)) / nsecPerMsec
b = strconv.AppendFloat(nil, msec, 'f', -1, 64)
return b, nil
}
// type check
var _ json.Unmarshaler = (*JSONDuration)(nil)
// UnmarshalJSON implements the json.Marshaler interface for *JSONDuration.
func (d *JSONDuration) UnmarshalJSON(b []byte) (err error) {
if d == nil {
return fmt.Errorf("json duration is nil")
}
msec, err := strconv.ParseFloat(string(b), 64)
if err != nil {
return fmt.Errorf("parsing json time: %w", err)
}
*d = JSONDuration(int64(msec * nsecPerMsec))
return nil
}
// JSONTime is a time.Time that can be decoded from JSON and encoded into JSON
// according to our API conventions.
type JSONTime time.Time
// type check
var _ json.Marshaler = JSONTime{}
// MarshalJSON implements the json.Marshaler interface for JSONTime. err is
// always nil.
func (t JSONTime) MarshalJSON() (b []byte, err error) {
msec := float64(time.Time(t).UnixNano()) / nsecPerMsec
b = strconv.AppendFloat(nil, msec, 'f', -1, 64)
return b, nil
}
// type check
var _ json.Unmarshaler = (*JSONTime)(nil)
// UnmarshalJSON implements the json.Marshaler interface for *JSONTime.
func (t *JSONTime) UnmarshalJSON(b []byte) (err error) {
if t == nil {
return fmt.Errorf("json time is nil")
}
msec, err := strconv.ParseFloat(string(b), 64)
if err != nil {
return fmt.Errorf("parsing json time: %w", err)
}
*t = JSONTime(time.Unix(0, int64(msec*nsecPerMsec)).UTC())
return nil
}
// WriteJSONResponse writes headers with the code, encodes resp into w, and logs
// any errors it encounters. r is used to get additional information from the
// request.
func WriteJSONResponse(w http.ResponseWriter, r *http.Request, code int, resp any) {
h := w.Header()
h.Set(httphdr.ContentType, HdrValApplicationJSON)
h.Set(httphdr.Server, UserAgent())
w.WriteHeader(code)
err := json.NewEncoder(w).Encode(resp)
if err != nil {
log.Error("aghhttp: writing json resp to %s %s: %s", r.Method, r.URL.Path, err)
}
}
// WriteJSONResponseOK writes headers with the code 200 OK, encodes v into w,
// and logs any errors it encounters. r is used to get additional information
// from the request.
func WriteJSONResponseOK(w http.ResponseWriter, r *http.Request, v any) {
WriteJSONResponse(w, r, http.StatusOK, v)
}
// ErrorCode is the error code as used by the HTTP API. See the ErrorCode
// definition in the OpenAPI specification.
type ErrorCode string
// ErrorCode constants.
//
// TODO(a.garipov): Expand and document codes.
const (
// ErrorCodeTMP000 is the temporary error code used for all errors.
ErrorCodeTMP000 = ""
)
// HTTPAPIErrorResp is the error response as used by the HTTP API. See the
// BadRequestResp, InternalServerErrorResp, and similar objects in the OpenAPI
// specification.
type HTTPAPIErrorResp struct {
Code ErrorCode `json:"code"`
Msg string `json:"msg"`
}
// WriteJSONResponseError encodes err as a JSON error into w, and logs any
// errors it encounters. r is used to get additional information from the
// request.
func WriteJSONResponseError(w http.ResponseWriter, r *http.Request, err error) {
log.Error("aghhttp: writing json error to %s %s: %s", r.Method, r.URL.Path, err)
WriteJSONResponse(w, r, http.StatusUnprocessableEntity, &HTTPAPIErrorResp{
Code: ErrorCodeTMP000,
Msg: err.Error(),
})
}

View File

@@ -0,0 +1,114 @@
package aghhttp_test
import (
"encoding/json"
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// testJSONTime is the JSON time for tests.
var testJSONTime = aghhttp.JSONTime(time.Unix(1_234_567_890, 123_456_000).UTC())
// testJSONTimeStr is the string with the JSON encoding of testJSONTime.
const testJSONTimeStr = "1234567890123.456"
func TestJSONTime_MarshalJSON(t *testing.T) {
testCases := []struct {
name string
wantErrMsg string
in aghhttp.JSONTime
want []byte
}{{
name: "unix_zero",
wantErrMsg: "",
in: aghhttp.JSONTime(time.Unix(0, 0)),
want: []byte("0"),
}, {
name: "empty",
wantErrMsg: "",
in: aghhttp.JSONTime{},
want: []byte("-6795364578871.345"),
}, {
name: "time",
wantErrMsg: "",
in: testJSONTime,
want: []byte(testJSONTimeStr),
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got, err := tc.in.MarshalJSON()
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
assert.Equal(t, tc.want, got)
})
}
t.Run("json", func(t *testing.T) {
in := &struct {
A aghhttp.JSONTime
}{
A: testJSONTime,
}
got, err := json.Marshal(in)
require.NoError(t, err)
assert.Equal(t, []byte(`{"A":`+testJSONTimeStr+`}`), got)
})
}
func TestJSONTime_UnmarshalJSON(t *testing.T) {
testCases := []struct {
name string
wantErrMsg string
want aghhttp.JSONTime
data []byte
}{{
name: "time",
wantErrMsg: "",
want: testJSONTime,
data: []byte(testJSONTimeStr),
}, {
name: "bad",
wantErrMsg: `parsing json time: strconv.ParseFloat: parsing "{}": ` +
`invalid syntax`,
want: aghhttp.JSONTime{},
data: []byte(`{}`),
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var got aghhttp.JSONTime
err := got.UnmarshalJSON(tc.data)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
assert.Equal(t, tc.want, got)
})
}
t.Run("nil", func(t *testing.T) {
err := (*aghhttp.JSONTime)(nil).UnmarshalJSON([]byte("0"))
require.Error(t, err)
msg := err.Error()
assert.Equal(t, "json time is nil", msg)
})
t.Run("json", func(t *testing.T) {
want := testJSONTime
var got struct {
A aghhttp.JSONTime
}
err := json.Unmarshal([]byte(`{"A":`+testJSONTimeStr+`}`), &got)
require.NoError(t, err)
assert.Equal(t, want, got.A)
})
}

View File

@@ -60,7 +60,7 @@ func ifaceIPv4Subnet(iface *net.Interface) (subnet netip.Prefix, err error) {
}
if ip = ip.To4(); ip != nil {
return netip.PrefixFrom(netip.AddrFrom4(*(*[4]byte)(ip)), maskLen), nil
return netip.PrefixFrom(netip.AddrFrom4([4]byte(ip)), maskLen), nil
}
}

View File

@@ -1,25 +1,19 @@
package aghnet
import (
"bufio"
"fmt"
"io"
"io/fs"
"net/netip"
"path"
"strings"
"sync"
"sync/atomic"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
"github.com/AdguardTeam/urlfilter/rules"
"github.com/miekg/dns"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
)
// DefaultHostsPaths returns the slice of paths default for the operating system
@@ -29,95 +23,51 @@ func DefaultHostsPaths() (paths []string) {
return defaultHostsPaths()
}
// requestMatcher combines the logic for matching requests and translating the
// appropriate rules.
type requestMatcher struct {
// stateLock protects all the fields of requestMatcher.
stateLock *sync.RWMutex
// rulesStrg stores the rules obtained from the hosts' file.
rulesStrg *filterlist.RuleStorage
// engine serves rulesStrg.
engine *urlfilter.DNSEngine
// translator maps generated $dnsrewrite rules into hosts-syntax rules.
//
// TODO(e.burkov): Store the filename from which the rule was parsed.
translator map[string]string
}
// MatchRequest processes the request rewriting hostnames and addresses read
// from the operating system's hosts files. res is nil for any request having
// not an A/AAAA or PTR type, see man 5 hosts.
//
// It's safe for concurrent use.
func (rm *requestMatcher) MatchRequest(
req *urlfilter.DNSRequest,
) (res *urlfilter.DNSResult, ok bool) {
switch req.DNSType {
case dns.TypeA, dns.TypeAAAA, dns.TypePTR:
log.Debug(
"%s: handling %s request for %s",
hostsContainerPrefix,
dns.Type(req.DNSType),
req.Hostname,
)
rm.stateLock.RLock()
defer rm.stateLock.RUnlock()
return rm.engine.MatchRequest(req)
default:
return nil, false
// MatchAddr returns the records for the IP address.
func (hc *HostsContainer) MatchAddr(ip netip.Addr) (recs []*hostsfile.Record) {
cur := hc.current.Load()
if cur == nil {
return nil
}
return cur.addrs[ip]
}
// Translate returns the source hosts-syntax rule for the generated dnsrewrite
// rule or an empty string if the last doesn't exist. The returned rules are in
// a processed format like:
//
// ip host1 host2 ...
func (rm *requestMatcher) Translate(rule string) (hostRule string) {
rm.stateLock.RLock()
defer rm.stateLock.RUnlock()
// MatchName returns the records for the hostname.
func (hc *HostsContainer) MatchName(name string) (recs []*hostsfile.Record) {
cur := hc.current.Load()
if cur != nil {
recs = cur.names[name]
}
return rm.translator[rule]
}
// resetEng updates container's engine and the translation map.
func (rm *requestMatcher) resetEng(rulesStrg *filterlist.RuleStorage, tr map[string]string) {
rm.stateLock.Lock()
defer rm.stateLock.Unlock()
rm.rulesStrg = rulesStrg
rm.engine = urlfilter.NewDNSEngine(rm.rulesStrg)
rm.translator = tr
return recs
}
// hostsContainerPrefix is a prefix for logging and wrapping errors in
// HostsContainer's methods.
const hostsContainerPrefix = "hosts container"
// Hosts is a map of IP addresses to the records, as it primarily stored in the
// [HostsContainer]. It should not be accessed for writing since it may be read
// concurrently, users should clone it before modifying.
//
// The order of records for each address is preserved from original files, but
// the order of the addresses, being a map key, is not.
//
// TODO(e.burkov): Probably, this should be a sorted slice of records.
type Hosts map[netip.Addr][]*hostsfile.Record
// HostsContainer stores the relevant hosts database provided by the OS and
// processes both A/AAAA and PTR DNS requests for those.
//
// TODO(e.burkov): Improve API and move to golibs.
type HostsContainer struct {
// requestMatcher matches the requests and translates the rules. It's
// embedded to implement MatchRequest and Translate for *HostsContainer.
//
// TODO(a.garipov, e.burkov): Consider fully merging into HostsContainer.
requestMatcher
// done is the channel to sign closing the container.
done chan struct{}
// updates is the channel for receiving updated hosts.
updates chan HostsRecords
updates chan Hosts
// last is the set of hosts that was cached within last detected change.
last HostsRecords
// current is the last set of hosts parsed.
current atomic.Pointer[hostsIndex]
// fsys is the working file system to read hosts files from.
fsys fs.FS
@@ -127,30 +77,6 @@ type HostsContainer struct {
// patterns stores specified paths in the fs.Glob-compatible form.
patterns []string
// listID is the identifier for the list of generated rules.
listID int
}
// HostsRecords is a mapping of an IP address to its hosts data.
type HostsRecords map[netip.Addr]*HostsRecord
// HostsRecord represents a single hosts file record.
type HostsRecord struct {
Aliases *stringutil.Set
Canonical string
}
// Equal returns true if all fields of rec are equal to field in other or they
// both are nil.
func (rec *HostsRecord) Equal(other *HostsRecord) (ok bool) {
if rec == nil {
return other == nil
} else if other == nil {
return false
}
return rec.Canonical == other.Canonical && rec.Aliases.Equal(other.Aliases)
}
// ErrNoHostsPaths is returned when there are no valid paths to watch passed to
@@ -162,7 +88,6 @@ const ErrNoHostsPaths errors.Error = "no valid paths to hosts files provided"
// shouldn't be empty and each of paths should locate either a file or a
// directory in fsys. fsys and w must be non-nil.
func NewHostsContainer(
listID int,
fsys fs.FS,
w aghos.FSWatcher,
paths ...string,
@@ -182,12 +107,8 @@ func NewHostsContainer(
}
hc = &HostsContainer{
requestMatcher: requestMatcher{
stateLock: &sync.RWMutex{},
},
listID: listID,
done: make(chan struct{}, 1),
updates: make(chan HostsRecords, 1),
updates: make(chan Hosts, 1),
fsys: fsys,
watcher: w,
patterns: patterns,
@@ -233,7 +154,7 @@ func (hc *HostsContainer) Close() (err error) {
}
// Upd returns the channel into which the updates are sent.
func (hc *HostsContainer) Upd() (updates <-chan HostsRecords) {
func (hc *HostsContainer) Upd() (updates <-chan Hosts) {
return hc.updates
}
@@ -280,7 +201,7 @@ func (hc *HostsContainer) handleEvents() {
}
if err := hc.refresh(); err != nil {
log.Error("%s: %s", hostsContainerPrefix, err)
log.Error("%s: warning: refreshing: %s", hostsContainerPrefix, err)
}
case _, ok = <-hc.done:
// Go on.
@@ -288,198 +209,83 @@ func (hc *HostsContainer) handleEvents() {
}
}
// hostsParser is a helper type to parse rules from the operating system's hosts
// file. It exists for only a single refreshing session.
type hostsParser struct {
// rulesBuilder builds the resulting rules list content.
rulesBuilder *strings.Builder
// translations maps generated rules into actual hosts file lines.
translations map[string]string
// table stores only the unique IP-hostname pairs. It's also sent to the
// updates channel afterwards.
table HostsRecords
}
// newHostsParser creates a new *hostsParser with buffers of size taken from the
// previous parse.
func (hc *HostsContainer) newHostsParser() (hp *hostsParser) {
return &hostsParser{
rulesBuilder: &strings.Builder{},
translations: map[string]string{},
table: make(HostsRecords, len(hc.last)),
}
}
// parseFile is a aghos.FileWalker for parsing the files with hosts syntax. It
// never signs to stop walking and never returns any additional patterns.
//
// See man hosts(5).
func (hp *hostsParser) parseFile(r io.Reader) (patterns []string, cont bool, err error) {
s := bufio.NewScanner(r)
for s.Scan() {
ip, hosts := hp.parseLine(s.Text())
if ip == (netip.Addr{}) || len(hosts) == 0 {
continue
}
hp.addRecord(ip, hosts)
}
return nil, true, s.Err()
}
// parseLine parses the line having the hosts syntax ignoring invalid ones.
func (hp *hostsParser) parseLine(line string) (ip netip.Addr, hosts []string) {
fields := strings.Fields(line)
if len(fields) < 2 {
return netip.Addr{}, nil
}
ip, err := netip.ParseAddr(fields[0])
if err != nil {
return netip.Addr{}, nil
}
for _, f := range fields[1:] {
hashIdx := strings.IndexByte(f, '#')
if hashIdx == 0 {
// The rest of the fields are a part of the comment so return.
break
} else if hashIdx > 0 {
// Only a part of the field is a comment.
f = f[:hashIdx]
}
// Make sure that invalid hosts aren't turned into rules.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/3946.
//
// TODO(e.burkov): Investigate if hosts may contain DNS-SD domains.
err = netutil.ValidateHostname(f)
if err != nil {
log.Error("%s: host %q is invalid, ignoring", hostsContainerPrefix, f)
continue
}
hosts = append(hosts, f)
}
return ip, hosts
}
// addRecord puts the record for the IP address to the rules builder if needed.
// The first host is considered to be the canonical name for the IP address.
// hosts must have at least one name.
func (hp *hostsParser) addRecord(ip netip.Addr, hosts []string) {
line := strings.Join(append([]string{ip.String()}, hosts...), " ")
rec, ok := hp.table[ip]
if !ok {
rec = &HostsRecord{
Aliases: stringutil.NewSet(),
}
rec.Canonical, hosts = hosts[0], hosts[1:]
hp.addRules(ip, rec.Canonical, line)
hp.table[ip] = rec
}
for _, host := range hosts {
if rec.Canonical == host || rec.Aliases.Has(host) {
continue
}
rec.Aliases.Add(host)
hp.addRules(ip, host, line)
}
}
// addRules adds rules and rule translations for the line.
func (hp *hostsParser) addRules(ip netip.Addr, host, line string) {
rule, rulePtr := hp.writeRules(host, ip)
hp.translations[rule], hp.translations[rulePtr] = line, line
log.Debug("%s: added ip-host pair %q-%q", hostsContainerPrefix, ip, host)
}
// writeRules writes the actual rule for the qtype and the PTR for the host-ip
// pair into internal builders.
func (hp *hostsParser) writeRules(host string, ip netip.Addr) (rule, rulePtr string) {
// TODO(a.garipov): Add a netip.Addr version to netutil.
arpa, err := netutil.IPToReversedAddr(ip.AsSlice())
if err != nil {
return "", ""
}
const (
nl = "\n"
rwSuccess = "^$dnsrewrite=NOERROR;"
rwSuccessPTR = "^$dnsrewrite=NOERROR;PTR;"
modLen = len(rules.MaskPipe) + len(rwSuccess) + len(";")
modLenPTR = len(rules.MaskPipe) + len(rwSuccessPTR)
)
var qtype string
// The validation of the IP address has been performed earlier so it is
// guaranteed to be either an IPv4 or an IPv6.
if ip.Is4() {
qtype = "A"
} else {
qtype = "AAAA"
}
ipStr := ip.String()
fqdn := dns.Fqdn(host)
ruleBuilder := &strings.Builder{}
ruleBuilder.Grow(modLen + len(host) + len(qtype) + len(ipStr))
stringutil.WriteToBuilder(ruleBuilder, rules.MaskPipe, host, rwSuccess, qtype, ";", ipStr)
rule = ruleBuilder.String()
ruleBuilder.Reset()
ruleBuilder.Grow(modLenPTR + len(arpa) + len(fqdn))
stringutil.WriteToBuilder(ruleBuilder, rules.MaskPipe, arpa, rwSuccessPTR, fqdn)
rulePtr = ruleBuilder.String()
hp.rulesBuilder.Grow(len(rule) + len(rulePtr) + 2*len(nl))
stringutil.WriteToBuilder(hp.rulesBuilder, rule, nl, rulePtr, nl)
return rule, rulePtr
}
// sendUpd tries to send the parsed data to the ch.
func (hp *hostsParser) sendUpd(ch chan HostsRecords) {
func (hc *HostsContainer) sendUpd(recs Hosts) {
log.Debug("%s: sending upd", hostsContainerPrefix)
upd := hp.table
ch := hc.updates
select {
case ch <- upd:
case ch <- recs:
// Updates are delivered. Go on.
case <-ch:
ch <- upd
ch <- recs
log.Debug("%s: replaced the last update", hostsContainerPrefix)
case ch <- upd:
case ch <- recs:
// The previous update was just read and the next one pushed. Go on.
default:
log.Error("%s: the updates channel is broken", hostsContainerPrefix)
}
}
// newStrg creates a new rules storage from parsed data.
func (hp *hostsParser) newStrg(id int) (s *filterlist.RuleStorage, err error) {
return filterlist.NewRuleStorage([]filterlist.RuleList{&filterlist.StringRuleList{
ID: id,
RulesText: hp.rulesBuilder.String(),
IgnoreCosmetic: true,
}})
// hostsIndex is a [hostsfile.Set] to enumerate all the records.
type hostsIndex struct {
// addrs maps IP addresses to the records.
addrs Hosts
// names maps hostnames to the records.
names map[string][]*hostsfile.Record
}
// walk is a file walking function for hostsIndex.
func (idx *hostsIndex) walk(r io.Reader) (patterns []string, cont bool, err error) {
return nil, true, hostsfile.Parse(idx, r, nil)
}
// type check
var _ hostsfile.Set = (*hostsIndex)(nil)
// Add implements the [hostsfile.Set] interface for *hostsIndex.
func (idx *hostsIndex) Add(rec *hostsfile.Record) {
idx.addrs[rec.Addr] = append(idx.addrs[rec.Addr], rec)
for _, name := range rec.Names {
idx.names[name] = append(idx.names[name], rec)
}
}
// type check
var _ hostsfile.HandleSet = (*hostsIndex)(nil)
// HandleInvalid implements the [hostsfile.HandleSet] interface for *hostsIndex.
func (idx *hostsIndex) HandleInvalid(src string, _ []byte, err error) {
lineErr := &hostsfile.LineError{}
if !errors.As(err, &lineErr) {
// Must not happen if idx passed to [hostsfile.Parse].
return
} else if errors.Is(lineErr, hostsfile.ErrEmptyLine) {
// Ignore empty lines.
return
}
log.Info("%s: warning: parsing %q: %s", hostsContainerPrefix, src, lineErr)
}
// equalRecs is an equality function for [*hostsfile.Record].
func equalRecs(a, b *hostsfile.Record) (ok bool) {
return a.Addr == b.Addr && a.Source == b.Source && slices.Equal(a.Names, b.Names)
}
// equalRecSlices is an equality function for slices of [*hostsfile.Record].
func equalRecSlices(a, b []*hostsfile.Record) (ok bool) { return slices.EqualFunc(a, b, equalRecs) }
// Equal returns true if indexes are equal.
func (idx *hostsIndex) Equal(other *hostsIndex) (ok bool) {
if idx == nil {
return other == nil
} else if other == nil {
return false
}
return maps.EqualFunc(idx.addrs, other.addrs, equalRecSlices)
}
// refresh gets the data from specified files and propagates the updates if
@@ -489,27 +295,27 @@ func (hp *hostsParser) newStrg(id int) (s *filterlist.RuleStorage, err error) {
func (hc *HostsContainer) refresh() (err error) {
log.Debug("%s: refreshing", hostsContainerPrefix)
hp := hc.newHostsParser()
if _, err = aghos.FileWalker(hp.parseFile).Walk(hc.fsys, hc.patterns...); err != nil {
return fmt.Errorf("refreshing : %w", err)
var addrLen, nameLen int
last := hc.current.Load()
if last != nil {
addrLen, nameLen = len(last.addrs), len(last.names)
}
idx := &hostsIndex{
addrs: make(Hosts, addrLen),
names: make(map[string][]*hostsfile.Record, nameLen),
}
// hc.last is nil on the first refresh, so let that one through.
if hc.last != nil && maps.EqualFunc(hp.table, hc.last, (*HostsRecord).Equal) {
log.Debug("%s: no changes detected", hostsContainerPrefix)
return nil
}
defer hp.sendUpd(hc.updates)
hc.last = maps.Clone(hp.table)
var rulesStrg *filterlist.RuleStorage
if rulesStrg, err = hp.newStrg(hc.listID); err != nil {
return fmt.Errorf("initializing rules storage: %w", err)
_, err = aghos.FileWalker(idx.walk).Walk(hc.fsys, hc.patterns...)
if err != nil {
// Don't wrap the error since it's informative enough as is.
return err
}
hc.resetEng(rulesStrg, hp.translations)
// TODO(e.burkov): Serialize updates using time.
if !last.Equal(idx) {
hc.current.Store(idx)
hc.sendUpd(idx.addrs)
}
return nil
}

View File

@@ -2,13 +2,11 @@ package aghnet
import (
"io/fs"
"net/netip"
"path"
"testing"
"testing/fstest"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil/fakefs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -76,69 +74,3 @@ func TestHostsContainer_PathsToPatterns(t *testing.T) {
assert.ErrorIs(t, err, errStat)
})
}
func TestUniqueRules_ParseLine(t *testing.T) {
ip := netutil.IPv4Localhost()
ipStr := ip.String()
testCases := []struct {
name string
line string
wantIP netip.Addr
wantHosts []string
}{{
name: "simple",
line: ipStr + ` hostname`,
wantIP: ip,
wantHosts: []string{"hostname"},
}, {
name: "aliases",
line: ipStr + ` hostname alias`,
wantIP: ip,
wantHosts: []string{"hostname", "alias"},
}, {
name: "invalid_line",
line: ipStr,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "invalid_line_hostname",
line: ipStr + ` # hostname`,
wantIP: ip,
wantHosts: nil,
}, {
name: "commented_aliases",
line: ipStr + ` hostname # alias`,
wantIP: ip,
wantHosts: []string{"hostname"},
}, {
name: "whole_comment",
line: `# ` + ipStr + ` hostname`,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "partial_comment",
line: ipStr + ` host#name`,
wantIP: ip,
wantHosts: []string{"host"},
}, {
name: "empty",
line: ``,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "bad_hosts",
line: ipStr + ` bad..host bad._tld empty.tld. ok.host`,
wantIP: ip,
wantHosts: []string{"ok.host"},
}}
for _, tc := range testCases {
hp := hostsParser{}
t.Run(tc.name, func(t *testing.T) {
got, hosts := hp.parseLine(tc.line)
assert.Equal(t, tc.wantIP, got)
assert.Equal(t, tc.wantHosts, hosts)
})
}
}

View File

@@ -1,9 +1,9 @@
package aghnet_test
import (
"net"
"net/netip"
"path"
"strings"
"path/filepath"
"sync/atomic"
"testing"
"testing/fstest"
@@ -13,18 +13,146 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/rules"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// nl is a newline character.
const nl = "\n"
// Variables mirroring the etc_hosts file from testdata.
var (
addr1000 = netip.MustParseAddr("1.0.0.0")
addr1001 = netip.MustParseAddr("1.0.0.1")
addr1002 = netip.MustParseAddr("1.0.0.2")
addr1003 = netip.MustParseAddr("1.0.0.3")
addr1004 = netip.MustParseAddr("1.0.0.4")
addr1357 = netip.MustParseAddr("1.3.5.7")
addr4216 = netip.MustParseAddr("4.2.1.6")
addr7531 = netip.MustParseAddr("7.5.3.1")
addr0 = netip.MustParseAddr("::")
addr1 = netip.MustParseAddr("::1")
addr2 = netip.MustParseAddr("::2")
addr3 = netip.MustParseAddr("::3")
addr4 = netip.MustParseAddr("::4")
addr42 = netip.MustParseAddr("::42")
addr13 = netip.MustParseAddr("::13")
addr31 = netip.MustParseAddr("::31")
hostsSrc = "./" + filepath.Join("./testdata", "etc_hosts")
testHosts = map[netip.Addr][]*hostsfile.Record{
addr1000: {{
Addr: addr1000,
Source: hostsSrc,
Names: []string{"hello", "hello.world"},
}, {
Addr: addr1000,
Source: hostsSrc,
Names: []string{"hello.world.again"},
}, {
Addr: addr1000,
Source: hostsSrc,
Names: []string{"hello.world"},
}},
addr1001: {{
Addr: addr1001,
Source: hostsSrc,
Names: []string{"simplehost"},
}, {
Addr: addr1001,
Source: hostsSrc,
Names: []string{"simplehost"},
}},
addr1002: {{
Addr: addr1002,
Source: hostsSrc,
Names: []string{"a.whole", "lot.of", "aliases", "for.testing"},
}},
addr1003: {{
Addr: addr1003,
Source: hostsSrc,
Names: []string{"*"},
}},
addr1004: {{
Addr: addr1004,
Source: hostsSrc,
Names: []string{"*.com"},
}},
addr1357: {{
Addr: addr1357,
Source: hostsSrc,
Names: []string{"domain4", "domain4.alias"},
}},
addr7531: {{
Addr: addr7531,
Source: hostsSrc,
Names: []string{"domain4.alias", "domain4"},
}},
addr4216: {{
Addr: addr4216,
Source: hostsSrc,
Names: []string{"domain", "domain.alias"},
}},
addr0: {{
Addr: addr0,
Source: hostsSrc,
Names: []string{"hello", "hello.world"},
}, {
Addr: addr0,
Source: hostsSrc,
Names: []string{"hello.world.again"},
}, {
Addr: addr0,
Source: hostsSrc,
Names: []string{"hello.world"},
}},
addr1: {{
Addr: addr1,
Source: hostsSrc,
Names: []string{"simplehost"},
}, {
Addr: addr1,
Source: hostsSrc,
Names: []string{"simplehost"},
}},
addr2: {{
Addr: addr2,
Source: hostsSrc,
Names: []string{"a.whole", "lot.of", "aliases", "for.testing"},
}},
addr3: {{
Addr: addr3,
Source: hostsSrc,
Names: []string{"*"},
}},
addr4: {{
Addr: addr4,
Source: hostsSrc,
Names: []string{"*.com"},
}},
addr42: {{
Addr: addr42,
Source: hostsSrc,
Names: []string{"domain.alias", "domain"},
}},
addr13: {{
Addr: addr13,
Source: hostsSrc,
Names: []string{"domain6", "domain6.alias"},
}},
addr31: {{
Addr: addr31,
Source: hostsSrc,
Names: []string{"domain6.alias", "domain6"},
}},
}
)
func TestNewHostsContainer(t *testing.T) {
const dirname = "dir"
const filename = "file1"
@@ -73,7 +201,7 @@ func TestNewHostsContainer(t *testing.T) {
return eventsCh
}
hc, err := aghnet.NewHostsContainer(0, testFS, &aghtest.FSWatcher{
hc, err := aghnet.NewHostsContainer(testFS, &aghtest.FSWatcher{
OnEvents: onEvents,
OnAdd: onAdd,
OnClose: func() (err error) { return nil },
@@ -99,7 +227,7 @@ func TestNewHostsContainer(t *testing.T) {
t.Run("nil_fs", func(t *testing.T) {
require.Panics(t, func() {
_, _ = aghnet.NewHostsContainer(0, nil, &aghtest.FSWatcher{
_, _ = aghnet.NewHostsContainer(nil, &aghtest.FSWatcher{
// Those shouldn't panic.
OnEvents: func() (e <-chan struct{}) { return nil },
OnAdd: func(name string) (err error) { return nil },
@@ -110,7 +238,7 @@ func TestNewHostsContainer(t *testing.T) {
t.Run("nil_watcher", func(t *testing.T) {
require.Panics(t, func() {
_, _ = aghnet.NewHostsContainer(0, testFS, nil, p)
_, _ = aghnet.NewHostsContainer(testFS, nil, p)
})
})
@@ -123,7 +251,7 @@ func TestNewHostsContainer(t *testing.T) {
OnClose: func() (err error) { return nil },
}
hc, err := aghnet.NewHostsContainer(0, testFS, errWatcher, p)
hc, err := aghnet.NewHostsContainer(testFS, errWatcher, p)
require.ErrorIs(t, err, errOnAdd)
assert.Nil(t, hc)
@@ -136,6 +264,9 @@ func TestHostsContainer_refresh(t *testing.T) {
ip := netutil.IPv4Localhost()
ipStr := ip.String()
anotherIPStr := "1.2.3.4"
anotherIP := netip.MustParseAddr(anotherIPStr)
testFS := fstest.MapFS{"dir/file1": &fstest.MapFile{Data: []byte(ipStr + ` hostname` + nl)}}
// event is a convenient alias for an empty struct{} to emit test events.
@@ -154,40 +285,44 @@ func TestHostsContainer_refresh(t *testing.T) {
OnClose: func() (err error) { return nil },
}
hc, err := aghnet.NewHostsContainer(0, testFS, w, "dir")
hc, err := aghnet.NewHostsContainer(testFS, w, "dir")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, hc.Close)
checkRefresh := func(t *testing.T, want *aghnet.HostsRecord) {
checkRefresh := func(t *testing.T, want aghnet.Hosts) {
t.Helper()
upd, ok := aghchan.MustReceive(hc.Upd(), 1*time.Second)
require.True(t, ok)
require.NotNil(t, upd)
assert.Len(t, upd, 1)
rec, ok := upd[ip]
require.True(t, ok)
require.NotNil(t, rec)
assert.Truef(t, rec.Equal(want), "%+v != %+v", rec, want)
assert.Equal(t, want, upd)
}
t.Run("initial_refresh", func(t *testing.T) {
checkRefresh(t, &aghnet.HostsRecord{
Aliases: stringutil.NewSet(),
Canonical: "hostname",
checkRefresh(t, aghnet.Hosts{
ip: {{
Addr: ip,
Source: "file1",
Names: []string{"hostname"},
}},
})
})
t.Run("second_refresh", func(t *testing.T) {
testFS["dir/file2"] = &fstest.MapFile{Data: []byte(ipStr + ` alias` + nl)}
testFS["dir/file2"] = &fstest.MapFile{Data: []byte(anotherIPStr + ` alias` + nl)}
eventsCh <- event{}
checkRefresh(t, &aghnet.HostsRecord{
Aliases: stringutil.NewSet("alias"),
Canonical: "hostname",
checkRefresh(t, aghnet.Hosts{
ip: {{
Addr: ip,
Source: "file1",
Names: []string{"hostname"},
}},
anotherIP: {{
Addr: anotherIP,
Source: "file2",
Names: []string{"alias"},
}},
})
})
@@ -198,12 +333,9 @@ func TestHostsContainer_refresh(t *testing.T) {
// Require the changes are written.
require.Eventually(t, func() bool {
res, ok := hc.MatchRequest(&urlfilter.DNSRequest{
Hostname: "hostname",
DNSType: dns.TypeA,
})
ips := hc.MatchName("hostname")
return !ok && res.DNSRewrites() == nil
return len(ips) == 0
}, 5*time.Second, time.Second/2)
// Make a change again.
@@ -212,285 +344,117 @@ func TestHostsContainer_refresh(t *testing.T) {
// Require the changes are written.
require.Eventually(t, func() bool {
res, ok := hc.MatchRequest(&urlfilter.DNSRequest{
Hostname: "hostname",
DNSType: dns.TypeA,
})
ips := hc.MatchName("hostname")
return !ok && res.DNSRewrites() != nil
return len(ips) > 0
}, 5*time.Second, time.Second/2)
assert.Len(t, hc.Upd(), 1)
})
}
func TestHostsContainer_Translate(t *testing.T) {
func TestHostsContainer_MatchName(t *testing.T) {
require.NoError(t, fstest.TestFS(testdata, "etc_hosts"))
stubWatcher := aghtest.FSWatcher{
OnEvents: func() (e <-chan struct{}) { return nil },
OnAdd: func(name string) (err error) { return nil },
OnClose: func() (err error) { return nil },
}
require.NoError(t, fstest.TestFS(testdata, "etc_hosts"))
hc, err := aghnet.NewHostsContainer(0, testdata, &stubWatcher, "etc_hosts")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, hc.Close)
testCases := []struct {
name string
rule string
wantTrans []string
}{{
name: "simplehost",
rule: "|simplehost^$dnsrewrite=NOERROR;A;1.0.0.1",
wantTrans: []string{"1.0.0.1", "simplehost"},
}, {
name: "hello",
rule: "|hello^$dnsrewrite=NOERROR;A;1.0.0.0",
wantTrans: []string{"1.0.0.0", "hello", "hello.world"},
}, {
name: "hello-alias",
rule: "|hello.world.again^$dnsrewrite=NOERROR;A;1.0.0.0",
wantTrans: []string{"1.0.0.0", "hello.world.again"},
}, {
name: "simplehost_v6",
rule: "|simplehost^$dnsrewrite=NOERROR;AAAA;::1",
wantTrans: []string{"::1", "simplehost"},
}, {
name: "hello_v6",
rule: "|hello^$dnsrewrite=NOERROR;AAAA;::",
wantTrans: []string{"::", "hello", "hello.world"},
}, {
name: "hello_v6-alias",
rule: "|hello.world.again^$dnsrewrite=NOERROR;AAAA;::",
wantTrans: []string{"::", "hello.world.again"},
}, {
name: "simplehost_ptr",
rule: "|1.0.0.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;simplehost.",
wantTrans: []string{"1.0.0.1", "simplehost"},
}, {
name: "hello_ptr",
rule: "|0.0.0.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;hello.",
wantTrans: []string{"1.0.0.0", "hello", "hello.world"},
}, {
name: "hello_ptr-alias",
rule: "|0.0.0.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;hello.world.again.",
wantTrans: []string{"1.0.0.0", "hello.world.again"},
}, {
name: "simplehost_ptr_v6",
rule: "|1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" +
"^$dnsrewrite=NOERROR;PTR;simplehost.",
wantTrans: []string{"::1", "simplehost"},
}, {
name: "hello_ptr_v6",
rule: "|0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" +
"^$dnsrewrite=NOERROR;PTR;hello.",
wantTrans: []string{"::", "hello", "hello.world"},
}, {
name: "hello_ptr_v6-alias",
rule: "|0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" +
"^$dnsrewrite=NOERROR;PTR;hello.world.again.",
wantTrans: []string{"::", "hello.world.again"},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got := stringutil.NewSet(strings.Fields(hc.Translate(tc.rule))...)
assert.True(t, stringutil.NewSet(tc.wantTrans...).Equal(got))
})
}
}
func TestHostsContainer(t *testing.T) {
const listID = 1234
require.NoError(t, fstest.TestFS(testdata, "etc_hosts"))
testCases := []struct {
req *urlfilter.DNSRequest
req string
name string
want []*rules.DNSRewrite
want []*hostsfile.Record
}{{
req: &urlfilter.DNSRequest{
Hostname: "simplehost",
DNSType: dns.TypeA,
},
req: "simplehost",
name: "simple",
want: []*rules.DNSRewrite{{
RCode: dns.RcodeSuccess,
Value: net.IPv4(1, 0, 0, 1),
RRType: dns.TypeA,
}, {
RCode: dns.RcodeSuccess,
Value: net.ParseIP("::1"),
RRType: dns.TypeAAAA,
}},
want: append(testHosts[addr1001], testHosts[addr1]...),
}, {
req: &urlfilter.DNSRequest{
Hostname: "hello.world",
DNSType: dns.TypeA,
},
req: "hello.world",
name: "hello_alias",
want: []*rules.DNSRewrite{{
RCode: dns.RcodeSuccess,
Value: net.IPv4(1, 0, 0, 0),
RRType: dns.TypeA,
}, {
RCode: dns.RcodeSuccess,
Value: net.ParseIP("::"),
RRType: dns.TypeAAAA,
}},
}, {
req: &urlfilter.DNSRequest{
Hostname: "hello.world.again",
DNSType: dns.TypeA,
want: []*hostsfile.Record{
testHosts[addr1000][0],
testHosts[addr1000][2],
testHosts[addr0][0],
testHosts[addr0][2],
},
}, {
req: "hello.world.again",
name: "other_line_alias",
want: []*rules.DNSRewrite{{
RCode: dns.RcodeSuccess,
Value: net.IPv4(1, 0, 0, 0),
RRType: dns.TypeA,
}, {
RCode: dns.RcodeSuccess,
Value: net.ParseIP("::"),
RRType: dns.TypeAAAA,
}},
}, {
req: &urlfilter.DNSRequest{
Hostname: "say.hello",
DNSType: dns.TypeA,
want: []*hostsfile.Record{
testHosts[addr1000][1],
testHosts[addr0][1],
},
}, {
req: "say.hello",
name: "hello_subdomain",
want: []*rules.DNSRewrite{},
}, {
req: &urlfilter.DNSRequest{
Hostname: "say.hello.world",
DNSType: dns.TypeA,
},
name: "hello_alias_subdomain",
want: []*rules.DNSRewrite{},
}, {
req: &urlfilter.DNSRequest{
Hostname: "for.testing",
DNSType: dns.TypeA,
},
name: "lots_of_aliases",
want: []*rules.DNSRewrite{{
RCode: dns.RcodeSuccess,
RRType: dns.TypeA,
Value: net.IPv4(1, 0, 0, 2),
}, {
RCode: dns.RcodeSuccess,
RRType: dns.TypeAAAA,
Value: net.ParseIP("::2"),
}},
}, {
req: &urlfilter.DNSRequest{
Hostname: "1.0.0.1.in-addr.arpa",
DNSType: dns.TypePTR,
},
name: "reverse",
want: []*rules.DNSRewrite{{
RCode: dns.RcodeSuccess,
RRType: dns.TypePTR,
Value: "simplehost.",
}},
}, {
req: &urlfilter.DNSRequest{
Hostname: "nonexistent.example",
DNSType: dns.TypeA,
},
name: "non-existing",
want: []*rules.DNSRewrite{},
}, {
req: &urlfilter.DNSRequest{
Hostname: "1.0.0.1.in-addr.arpa",
DNSType: dns.TypeSRV,
},
name: "bad_type",
want: nil,
}, {
req: &urlfilter.DNSRequest{
Hostname: "domain",
DNSType: dns.TypeA,
},
req: "say.hello.world",
name: "hello_alias_subdomain",
want: nil,
}, {
req: "for.testing",
name: "lots_of_aliases",
want: append(testHosts[addr1002], testHosts[addr2]...),
}, {
req: "nonexistent.example",
name: "non-existing",
want: nil,
}, {
req: "domain",
name: "issue_4216_4_6",
want: []*rules.DNSRewrite{{
RCode: dns.RcodeSuccess,
RRType: dns.TypeA,
Value: net.IPv4(4, 2, 1, 6),
}, {
RCode: dns.RcodeSuccess,
RRType: dns.TypeAAAA,
Value: net.ParseIP("::42"),
}},
want: append(testHosts[addr4216], testHosts[addr42]...),
}, {
req: &urlfilter.DNSRequest{
Hostname: "domain4",
DNSType: dns.TypeA,
},
req: "domain4",
name: "issue_4216_4",
want: []*rules.DNSRewrite{{
RCode: dns.RcodeSuccess,
RRType: dns.TypeA,
Value: net.IPv4(7, 5, 3, 1),
}, {
RCode: dns.RcodeSuccess,
RRType: dns.TypeA,
Value: net.IPv4(1, 3, 5, 7),
}},
want: append(testHosts[addr1357], testHosts[addr7531]...),
}, {
req: &urlfilter.DNSRequest{
Hostname: "domain6",
DNSType: dns.TypeAAAA,
},
req: "domain6",
name: "issue_4216_6",
want: []*rules.DNSRewrite{{
RCode: dns.RcodeSuccess,
RRType: dns.TypeAAAA,
Value: net.ParseIP("::13"),
}, {
RCode: dns.RcodeSuccess,
RRType: dns.TypeAAAA,
Value: net.ParseIP("::31"),
}},
want: append(testHosts[addr13], testHosts[addr31]...),
}}
hc, err := aghnet.NewHostsContainer(testdata, &stubWatcher, "etc_hosts")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, hc.Close)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
recs := hc.MatchName(tc.req)
assert.Equal(t, tc.want, recs)
})
}
}
func TestHostsContainer_MatchAddr(t *testing.T) {
require.NoError(t, fstest.TestFS(testdata, "etc_hosts"))
stubWatcher := aghtest.FSWatcher{
OnEvents: func() (e <-chan struct{}) { return nil },
OnAdd: func(name string) (err error) { return nil },
OnClose: func() (err error) { return nil },
}
hc, err := aghnet.NewHostsContainer(listID, testdata, &stubWatcher, "etc_hosts")
hc, err := aghnet.NewHostsContainer(testdata, &stubWatcher, "etc_hosts")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, hc.Close)
testCases := []struct {
req netip.Addr
name string
want []*hostsfile.Record
}{{
req: netip.AddrFrom4([4]byte{1, 0, 0, 1}),
name: "reverse",
want: testHosts[addr1001],
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
res, ok := hc.MatchRequest(tc.req)
require.False(t, ok)
if tc.want == nil {
assert.Nil(t, res)
return
}
require.NotNil(t, res)
rewrites := res.DNSRewrites()
require.Len(t, rewrites, len(tc.want))
for i, rewrite := range rewrites {
require.Equal(t, listID, rewrite.FilterListID)
rw := rewrite.DNSRewrite
require.NotNil(t, rw)
assert.Equal(t, tc.want[i], rw)
}
recs := hc.MatchAddr(tc.req)
assert.Equal(t, tc.want, recs)
})
}
}

56
internal/aghnet/ignore.go Normal file
View File

@@ -0,0 +1,56 @@
package aghnet
import (
"strings"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
"golang.org/x/exp/slices"
)
// IgnoreEngine contains the list of rules for ignoring hostnames and matches
// them.
//
// TODO(s.chzhen): Move all urlfilter stuff to aghfilter.
type IgnoreEngine struct {
// engine is the filtering engine that can match rules for ignoring
// hostnames.
engine *urlfilter.DNSEngine
// ignored is the list of rules for ignoring hostnames.
ignored []string
}
// NewIgnoreEngine creates a new instance of the IgnoreEngine and stores the
// list of rules for ignoring hostnames.
func NewIgnoreEngine(ignored []string) (e *IgnoreEngine, err error) {
ruleList := &filterlist.StringRuleList{
RulesText: strings.ToLower(strings.Join(ignored, "\n")),
IgnoreCosmetic: true,
}
ruleStorage, err := filterlist.NewRuleStorage([]filterlist.RuleList{ruleList})
if err != nil {
return nil, err
}
return &IgnoreEngine{
engine: urlfilter.NewDNSEngine(ruleStorage),
ignored: ignored,
}, nil
}
// Has returns true if IgnoreEngine matches the host.
func (e *IgnoreEngine) Has(host string) (ignore bool) {
if e == nil {
return false
}
_, ignore = e.engine.Match(host)
return ignore
}
// Values returns a copy of list of rules for ignoring hostnames.
func (e *IgnoreEngine) Values() (ignored []string) {
return slices.Clone(e.ignored)
}

View File

@@ -0,0 +1,46 @@
package aghnet_test
import (
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/stretchr/testify/require"
)
func TestIgnoreEngine_Has(t *testing.T) {
hostnames := []string{
"*.example.com",
"example.com",
"|.^",
}
engine, err := aghnet.NewIgnoreEngine(hostnames)
require.NotNil(t, engine)
require.NoError(t, err)
testCases := []struct {
name string
host string
ignore bool
}{{
name: "basic",
host: "example.com",
ignore: true,
}, {
name: "root",
host: ".",
ignore: true,
}, {
name: "wildcard",
host: "www.example.com",
ignore: true,
}, {
name: "not_ignored",
host: "something.com",
ignore: false,
}}
for _, tc := range testCases {
require.Equal(t, tc.ignore, engine.Has(tc.host))
}
}

View File

@@ -4,7 +4,6 @@ package aghnet
import (
"context"
"fmt"
"net"
"os"
"syscall"
@@ -24,20 +23,9 @@ func reuseAddrCtrl(_, _ string, c syscall.RawConn) (err error) {
}
})
const (
errMsg = "setting control options"
errMsgFmt = errMsg + ": %w"
)
err = errors.Join(err, cerr)
if err != nil && cerr != nil {
err = errors.List(errMsg, err, cerr)
} else if err != nil {
err = fmt.Errorf(errMsgFmt, err)
} else if cerr != nil {
err = fmt.Errorf(errMsgFmt, cerr)
}
return err
return errors.Annotate(err, "setting control options: %w")
}
// listenPacketReusable announces on the local network address additionally

View File

@@ -390,9 +390,5 @@ func (m *ipsetMgr) Close() (err error) {
errs = append(errs, err)
}
if len(errs) != 0 {
return errors.List("closing ipsets", errs...)
}
return nil
return errors.Annotate(errors.Join(errs...), "closing ipsets: %w")
}

View File

@@ -7,7 +7,6 @@ import (
"io/fs"
"net"
"net/netip"
"os"
"strings"
"testing"
@@ -18,9 +17,6 @@ import (
"github.com/stretchr/testify/require"
)
// testdata is the filesystem containing data for testing the package.
var testdata fs.FS = os.DirFS("./testdata")
// substRootDirFS replaces the aghos.RootDirFS function used throughout the
// package with fsys for tests ran under t.
func substRootDirFS(t testing.TB, fsys fs.FS) {

View File

@@ -113,7 +113,7 @@ func (w *osWatcher) handleEvents() {
}
// Skip the following events assuming that sometimes the same event
// occurrs several times.
// occurs several times.
for ok := true; ok; {
select {
case _, ok = <-ch:

View File

@@ -182,3 +182,8 @@ func IsReconfigureSignal(sig os.Signal) (ok bool) {
func IsShutdownSignal(sig os.Signal) (ok bool) {
return isShutdownSignal(sig)
}
// SendShutdownSignal sends the shutdown signal to the channel.
func SendShutdownSignal(c chan<- os.Signal) {
sendShutdownSignal(c)
}

View File

@@ -37,3 +37,7 @@ func isShutdownSignal(sig os.Signal) (ok bool) {
return false
}
}
func sendShutdownSignal(_ chan<- os.Signal) {
// On Unix we are already notified by the system.
}

View File

@@ -77,3 +77,7 @@ func isShutdownSignal(sig os.Signal) (ok bool) {
return false
}
}
func sendShutdownSignal(c chan<- os.Signal) {
c <- os.Interrupt
}

View File

@@ -4,12 +4,20 @@ package aghtest
import (
"crypto/sha256"
"io"
"net"
"net/netip"
"testing"
"github.com/AdguardTeam/golibs/log"
)
const (
// ReqHost is the common request host for filtering tests.
ReqHost = "www.host.example"
// ReqFQDN is the common request FQDN for filtering tests.
ReqFQDN = ReqHost + "."
)
// ReplaceLogWriter moves logger output to w and uses Cleanup method of t to
// revert changes.
func ReplaceLogWriter(t testing.TB, w io.Writer) {
@@ -38,8 +46,8 @@ func ReplaceLogLevel(t testing.TB, l log.Level) {
}
// HostToIPs is a helper that generates one IPv4 and one IPv6 address from host.
func HostToIPs(host string) (ipv4, ipv6 net.IP) {
func HostToIPs(host string) (ipv4, ipv6 netip.Addr) {
hash := sha256.Sum256([]byte(host))
return net.IP(hash[:4]), net.IP(hash[4:20])
return netip.AddrFrom4([4]byte(hash[:4])), netip.AddrFrom16([16]byte(hash[4:20]))
}

View File

@@ -1,4 +1,5 @@
package aghnet
// Package arpdb implements the Network Neighborhood Database.
package arpdb
import (
"bufio"
@@ -8,15 +9,25 @@ import (
"net/netip"
"sync"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"golang.org/x/exp/slices"
)
// ARPDB: The Network Neighborhood Database
// Variables and functions to substitute in tests.
var (
// aghosRunCommand is the function to run shell commands.
aghosRunCommand = aghos.RunCommand
// ARPDB stores and refreshes the network neighborhood reported by ARP (Address
// Resolution Protocol).
type ARPDB interface {
// rootDirFS is the filesystem pointing to the root directory.
rootDirFS = aghos.RootDirFS()
)
// Interface stores and refreshes the network neighborhood reported by ARP
// (Address Resolution Protocol).
type Interface interface {
// Refresh updates the stored data. It must be safe for concurrent use.
Refresh() (err error)
@@ -25,28 +36,24 @@ type ARPDB interface {
Neighbors() (ns []Neighbor)
}
// NewARPDB returns the ARPDB properly initialized for the OS.
func NewARPDB() (arp ARPDB) {
// New returns the [Interface] properly initialized for the OS.
func New() (arp Interface) {
return newARPDB()
}
// Empty ARPDB implementation
// EmptyARPDB is the ARPDB implementation that does nothing.
type EmptyARPDB struct{}
// Empty is the [Interface] implementation that does nothing.
type Empty struct{}
// type check
var _ ARPDB = EmptyARPDB{}
var _ Interface = Empty{}
// Refresh implements the ARPDB interface for EmptyARPContainer. It does
// Refresh implements the [Interface] interface for EmptyARPContainer. It does
// nothing and always returns nil error.
func (EmptyARPDB) Refresh() (err error) { return nil }
func (Empty) Refresh() (err error) { return nil }
// Neighbors implements the ARPDB interface for EmptyARPContainer. It always
// returns nil.
func (EmptyARPDB) Neighbors() (ns []Neighbor) { return nil }
// ARPDB Helper Types
// Neighbors implements the [Interface] interface for EmptyARPContainer. It
// always returns nil.
func (Empty) Neighbors() (ns []Neighbor) { return nil }
// Neighbor is the pair of IP address and MAC address reported by ARP.
type Neighbor struct {
@@ -70,8 +77,21 @@ func (n Neighbor) Clone() (clone Neighbor) {
}
}
// validatedHostname returns h if it's a valid hostname, or an empty string
// otherwise, logging the validation error.
func validatedHostname(h string) (host string) {
err := netutil.ValidateHostname(h)
if err != nil {
log.Debug("arpdb: parsing arp output: host: %s", err)
return ""
}
return h
}
// neighs is the helper type that stores neighbors to avoid copying its methods
// among all the ARPDB implementations.
// among all the [Interface] implementations.
type neighs struct {
mu *sync.RWMutex
ns []Neighbor
@@ -108,14 +128,12 @@ func (ns *neighs) reset(with []Neighbor) {
ns.ns = with
}
// Command ARPDB
// parseNeighsFunc parses the text from sc as if it'd be an output of some
// ARP-related command. lenHint is a hint for the size of the allocated slice
// of Neighbors.
type parseNeighsFunc func(sc *bufio.Scanner, lenHint int) (ns []Neighbor)
// cmdARPDB is the implementation of the ARPDB that uses command line to
// cmdARPDB is the implementation of the [Interface] that uses command line to
// retrieve data.
type cmdARPDB struct {
parse parseNeighsFunc
@@ -125,9 +143,9 @@ type cmdARPDB struct {
}
// type check
var _ ARPDB = (*cmdARPDB)(nil)
var _ Interface = (*cmdARPDB)(nil)
// Refresh implements the ARPDB interface for *cmdARPDB.
// Refresh implements the [Interface] interface for *cmdARPDB.
func (arp *cmdARPDB) Refresh() (err error) {
defer func() { err = errors.Annotate(err, "cmd arpdb: %w") }()
@@ -150,24 +168,22 @@ func (arp *cmdARPDB) Refresh() (err error) {
return nil
}
// Neighbors implements the ARPDB interface for *cmdARPDB.
// Neighbors implements the [Interface] interface for *cmdARPDB.
func (arp *cmdARPDB) Neighbors() (ns []Neighbor) {
return arp.ns.clone()
}
// Composite ARPDB
// arpdbs is the ARPDB that combines several ARPDB implementations and
// consequently switches between those.
// arpdbs is the [Interface] that combines several [Interface] implementations
// and consequently switches between those.
type arpdbs struct {
// arps is the set of ARPDB implementations to range through.
arps []ARPDB
// arps is the set of [Interface] implementations to range through.
arps []Interface
neighs
}
// newARPDBs returns a properly initialized *arpdbs. It begins refreshing from
// the first of arps.
func newARPDBs(arps ...ARPDB) (arp *arpdbs) {
func newARPDBs(arps ...Interface) (arp *arpdbs) {
return &arpdbs{
arps: arps,
neighs: neighs{
@@ -178,9 +194,9 @@ func newARPDBs(arps ...ARPDB) (arp *arpdbs) {
}
// type check
var _ ARPDB = (*arpdbs)(nil)
var _ Interface = (*arpdbs)(nil)
// Refresh implements the ARPDB interface for *arpdbs.
// Refresh implements the [Interface] interface for *arpdbs.
func (arp *arpdbs) Refresh() (err error) {
var errs []error
@@ -197,14 +213,10 @@ func (arp *arpdbs) Refresh() (err error) {
return nil
}
if len(errs) > 0 {
err = errors.List("each arpdb failed", errs...)
}
return err
return errors.Annotate(errors.Join(errs...), "each arpdb failed: %w")
}
// Neighbors implements the ARPDB interface for *arpdbs.
// Neighbors implements the [Interface] interface for *arpdbs.
//
// TODO(e.burkov): Think of a way to avoid cloning the slice twice.
func (arp *arpdbs) Neighbors() (ns []Neighbor) {

View File

@@ -1,6 +1,6 @@
//go:build darwin || freebsd
package aghnet
package arpdb
import (
"bufio"
@@ -10,7 +10,6 @@ import (
"sync"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
)
func newARPDB() (arp *cmdARPDB) {
@@ -44,16 +43,16 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
n := Neighbor{}
if ipStr := fields[1]; len(ipStr) < 2 {
ipStr := fields[1]
if len(ipStr) < 2 {
continue
} else if ip, err := netip.ParseAddr(ipStr[1 : len(ipStr)-1]); err != nil {
}
ip, err := netip.ParseAddr(ipStr[1 : len(ipStr)-1])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
continue
} else {
n.IP = ip
}
hwStr := fields[3]
@@ -62,19 +61,13 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
} else {
n.MAC = mac
}
host := fields[0]
err = netutil.ValidateHostname(host)
if err != nil {
log.Debug("arpdb: parsing arp output: host: %s", err)
} else {
n.Name = host
}
ns = append(ns, n)
ns = append(ns, Neighbor{
IP: ip,
MAC: mac,
Name: validatedHostname(fields[0]),
})
}
return ns

View File

@@ -1,6 +1,6 @@
//go:build darwin || freebsd
package aghnet
package arpdb
import (
"net"

View File

@@ -1,8 +1,12 @@
package aghnet
package arpdb
import (
"fmt"
"io/fs"
"net"
"net/netip"
"os"
"strings"
"sync"
"testing"
@@ -12,30 +16,78 @@ import (
"github.com/stretchr/testify/require"
)
func TestNewARPDB(t *testing.T) {
var a ARPDB
require.NotPanics(t, func() { a = NewARPDB() })
// testdata is the filesystem containing data for testing the package.
var testdata fs.FS = os.DirFS("./testdata")
// RunCmdFunc is the signature of aghos.RunCommand function.
type RunCmdFunc func(cmd string, args ...string) (code int, out []byte, err error)
// substShell replaces the the aghos.RunCommand function used throughout the
// package with rc for tests ran under t.
func substShell(t testing.TB, rc RunCmdFunc) {
t.Helper()
prev := aghosRunCommand
t.Cleanup(func() { aghosRunCommand = prev })
aghosRunCommand = rc
}
// mapShell is a substitution of aghos.RunCommand that maps the command to it's
// execution result. It's only needed to simplify testing.
//
// TODO(e.burkov): Perhaps put all the shell interactions behind an interface.
type mapShell map[string]struct {
err error
out string
code int
}
// theOnlyCmd returns mapShell that only handles a single command and arguments
// combination from cmd.
func theOnlyCmd(cmd string, code int, out string, err error) (s mapShell) {
return mapShell{cmd: {code: code, out: out, err: err}}
}
// RunCmd is a RunCmdFunc handled by s.
func (s mapShell) RunCmd(cmd string, args ...string) (code int, out []byte, err error) {
key := strings.Join(append([]string{cmd}, args...), " ")
ret, ok := s[key]
if !ok {
return 0, nil, fmt.Errorf("unexpected shell command %q", key)
}
return ret.code, []byte(ret.out), ret.err
}
func Test_New(t *testing.T) {
var a Interface
require.NotPanics(t, func() { a = New() })
assert.NotNil(t, a)
}
// TestARPDB is the mock implementation of ARPDB to use in tests.
// TODO(s.chzhen): Consider moving mocks into aghtest.
// TestARPDB is the mock implementation of [Interface] to use in tests.
type TestARPDB struct {
OnRefresh func() (err error)
OnNeighbors func() (ns []Neighbor)
}
// Refresh implements the ARPDB interface for *TestARPDB.
// type check
var _ Interface = (*TestARPDB)(nil)
// Refresh implements the [Interface] interface for *TestARPDB.
func (arp *TestARPDB) Refresh() (err error) {
return arp.OnRefresh()
}
// Neighbors implements the ARPDB interface for *TestARPDB.
// Neighbors implements the [Interface] interface for *TestARPDB.
func (arp *TestARPDB) Neighbors() (ns []Neighbor) {
return arp.OnNeighbors()
}
func TestARPDBS(t *testing.T) {
func Test_NewARPDBs(t *testing.T) {
knownIP := netip.MustParseAddr("1.2.3.4")
knownMAC := net.HardwareAddr{0xAB, 0xCD, 0xEF, 0xAB, 0xCD, 0xEF}
@@ -82,7 +134,7 @@ func TestARPDBS(t *testing.T) {
t.Run("fail_only", func(t *testing.T) {
t.Cleanup(clnp)
wantMsg := `each arpdb failed: 2 errors: "refresh failed", "refresh failed"`
wantMsg := "each arpdb failed: refresh failed\nrefresh failed"
a := newARPDBs(failDB, failDB)
err := a.Refresh()
@@ -195,7 +247,7 @@ func TestCmdARPDB_arpa(t *testing.T) {
}
func TestEmptyARPDB(t *testing.T) {
a := EmptyARPDB{}
a := Empty{}
t.Run("refresh", func(t *testing.T) {
var err error

View File

@@ -1,6 +1,6 @@
//go:build linux
package aghnet
package arpdb
import (
"bufio"
@@ -13,7 +13,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
)
@@ -68,9 +67,9 @@ type fsysARPDB struct {
}
// type check
var _ ARPDB = (*fsysARPDB)(nil)
var _ Interface = (*fsysARPDB)(nil)
// Refresh implements the ARPDB interface for *fsysARPDB.
// Refresh implements the [Interface] interface for *fsysARPDB.
func (arp *fsysARPDB) Refresh() (err error) {
var f fs.File
f, err = arp.fsys.Open(arp.filename)
@@ -88,21 +87,10 @@ func (arp *fsysARPDB) Refresh() (err error) {
ns := make([]Neighbor, 0, arp.ns.len())
for sc.Scan() {
ln := sc.Text()
fields := stringutil.SplitTrimmed(ln, " ")
if len(fields) != 6 {
continue
n := parseNeighbor(sc.Text())
if n != nil {
ns = append(ns, *n)
}
n := Neighbor{}
n.IP, err = netip.ParseAddr(fields[0])
if err != nil || n.IP.IsUnspecified() {
continue
} else if n.MAC, err = net.ParseMAC(fields[3]); err != nil {
continue
}
ns = append(ns, n)
}
arp.ns.reset(ns)
@@ -110,7 +98,30 @@ func (arp *fsysARPDB) Refresh() (err error) {
return nil
}
// Neighbors implements the ARPDB interface for *fsysARPDB.
// parseNeighbor parses line into *Neighbor.
func parseNeighbor(line string) (n *Neighbor) {
fields := stringutil.SplitTrimmed(line, " ")
if len(fields) != 6 {
return nil
}
ip, err := netip.ParseAddr(fields[0])
if err != nil || ip.IsUnspecified() {
return nil
}
mac, err := net.ParseMAC(fields[3])
if err != nil {
return nil
}
return &Neighbor{
IP: ip,
MAC: mac,
}
}
// Neighbors implements the [Interface] interface for *fsysARPDB.
func (arp *fsysARPDB) Neighbors() (ns []Neighbor) {
return arp.ns.clone()
}
@@ -135,15 +146,11 @@ func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
n := Neighbor{}
ip, err := netip.ParseAddr(fields[0])
if err != nil || n.IP.IsUnspecified() {
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
continue
} else {
n.IP = ip
}
hwStr := fields[3]
@@ -152,11 +159,12 @@ func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
} else {
n.MAC = mac
}
ns = append(ns, n)
ns = append(ns, Neighbor{
IP: ip,
MAC: mac,
})
}
return ns
@@ -176,35 +184,31 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
n := Neighbor{}
if ipStr := fields[1]; len(ipStr) < 2 {
ipStr := fields[1]
if len(ipStr) < 2 {
continue
} else if ip, err := netip.ParseAddr(ipStr[1 : len(ipStr)-1]); err != nil {
}
ip, err := netip.ParseAddr(ipStr[1 : len(ipStr)-1])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
continue
} else {
n.IP = ip
}
hwStr := fields[3]
if mac, err := net.ParseMAC(hwStr); err != nil {
mac, err := net.ParseMAC(hwStr)
if err != nil {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
} else {
n.MAC = mac
}
host := fields[0]
if verr := netutil.ValidateHostname(host); verr != nil {
log.Debug("arpdb: parsing arp output: host: %s", verr)
} else {
n.Name = host
}
ns = append(ns, n)
ns = append(ns, Neighbor{
IP: ip,
MAC: mac,
Name: validatedHostname(fields[0]),
})
}
return ns

View File

@@ -1,6 +1,6 @@
//go:build linux
package aghnet
package arpdb
import (
"net"

View File

@@ -1,6 +1,6 @@
//go:build openbsd
package aghnet
package arpdb
import (
"bufio"

View File

@@ -1,6 +1,6 @@
//go:build openbsd
package aghnet
package arpdb
import (
"net"

View File

@@ -1,6 +1,6 @@
//go:build windows
package aghnet
package arpdb
import (
"bufio"
@@ -8,6 +8,8 @@ import (
"net/netip"
"strings"
"sync"
"github.com/AdguardTeam/golibs/log"
)
func newARPDB() (arp *cmdARPDB) {
@@ -42,23 +44,24 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
n := Neighbor{}
ip, err := netip.ParseAddr(fields[0])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
continue
} else {
n.IP = ip
}
mac, err := net.ParseMAC(fields[1])
if err != nil {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
} else {
n.MAC = mac
}
ns = append(ns, n)
ns = append(ns, Neighbor{
IP: ip,
MAC: mac,
})
}
return ns

View File

@@ -1,6 +1,6 @@
//go:build windows
package aghnet
package arpdb
import (
"net"

View File

@@ -3,3 +3,52 @@
//
// TODO(a.garipov): Expand.
package client
import (
"encoding"
"fmt"
)
// Source represents the source from which the information about the client has
// been obtained.
type Source uint8
// Clients information sources. The order determines the priority.
const (
SourceNone Source = iota
SourceWHOIS
SourceARP
SourceRDNS
SourceDHCP
SourceHostsFile
SourcePersistent
)
// type check
var _ fmt.Stringer = Source(0)
// String returns a human-readable name of cs.
func (cs Source) String() (s string) {
switch cs {
case SourceWHOIS:
return "WHOIS"
case SourceARP:
return "ARP"
case SourceRDNS:
return "rDNS"
case SourceDHCP:
return "DHCP"
case SourceHostsFile:
return "etc/hosts"
default:
return ""
}
}
// type check
var _ encoding.TextMarshaler = Source(0)
// MarshalText implements encoding.TextMarshaler for the Source.
func (cs Source) MarshalText() (text []byte, err error) {
return []byte(cs.String()), nil
}

View File

@@ -1,4 +1,4 @@
package home
package confmigrate
import (
"testing"
@@ -11,12 +11,16 @@ import (
"github.com/stretchr/testify/require"
)
// TODO(a.garipov): Cover all migrations, use a testdata/ dir.
// TODO(e.burkov): Cover all migrations, use a testdata/ dir.
func TestUpgradeSchema1to2(t *testing.T) {
diskConf := testDiskConf(1)
err := upgradeSchema1to2(diskConf)
m := New(&Config{
WorkingDir: "",
})
err := m.migrateTo2(diskConf)
require.NoError(t, err)
require.Equal(t, diskConf["schema_version"], 2)
@@ -39,7 +43,7 @@ func TestUpgradeSchema1to2(t *testing.T) {
func TestUpgradeSchema2to3(t *testing.T) {
diskConf := testDiskConf(2)
err := upgradeSchema2to3(diskConf)
err := migrateTo3(diskConf)
require.NoError(t, err)
require.Equal(t, diskConf["schema_version"], 3)
@@ -52,7 +56,7 @@ func TestUpgradeSchema2to3(t *testing.T) {
bootstrapDNS := newDNSConf["bootstrap_dns"]
switch v := bootstrapDNS.(type) {
case []string:
case yarr:
require.Len(t, v, 1)
require.Equal(t, "8.8.8.8:53", v[0])
default:
@@ -78,21 +82,21 @@ func TestUpgradeSchema5to6(t *testing.T) {
name string
}{{
in: yobj{
"clients": []yobj{},
"clients": yarr{},
},
want: yobj{
"clients": []yobj{},
"clients": yarr{},
"schema_version": newSchemaVer,
},
wantErr: "",
name: "no_clients",
}, {
in: yobj{
"clients": []yobj{{"ip": "127.0.0.1"}},
"clients": yarr{yobj{"ip": "127.0.0.1"}},
},
want: yobj{
"clients": []yobj{{
"ids": []string{"127.0.0.1"},
"clients": yarr{yobj{
"ids": yarr{"127.0.0.1"},
"ip": "127.0.0.1",
}},
"schema_version": newSchemaVer,
@@ -101,11 +105,11 @@ func TestUpgradeSchema5to6(t *testing.T) {
name: "client_ip",
}, {
in: yobj{
"clients": []yobj{{"mac": "mac"}},
"clients": yarr{yobj{"mac": "mac"}},
},
want: yobj{
"clients": []yobj{{
"ids": []string{"mac"},
"clients": yarr{yobj{
"ids": yarr{"mac"},
"mac": "mac",
}},
"schema_version": newSchemaVer,
@@ -114,11 +118,11 @@ func TestUpgradeSchema5to6(t *testing.T) {
name: "client_mac",
}, {
in: yobj{
"clients": []yobj{{"ip": "127.0.0.1", "mac": "mac"}},
"clients": yarr{yobj{"ip": "127.0.0.1", "mac": "mac"}},
},
want: yobj{
"clients": []yobj{{
"ids": []string{"127.0.0.1", "mac"},
"clients": yarr{yobj{
"ids": yarr{"127.0.0.1", "mac"},
"ip": "127.0.0.1",
"mac": "mac",
}},
@@ -128,29 +132,29 @@ func TestUpgradeSchema5to6(t *testing.T) {
name: "client_ip_mac",
}, {
in: yobj{
"clients": []yobj{{"ip": 1, "mac": "mac"}},
"clients": yarr{yobj{"ip": 1, "mac": "mac"}},
},
want: yobj{
"clients": []yobj{{"ip": 1, "mac": "mac"}},
"clients": yarr{yobj{"ip": 1, "mac": "mac"}},
"schema_version": newSchemaVer,
},
wantErr: "client.ip is not a string: 1",
wantErr: `client at index 0: unexpected type of "ip": int`,
name: "inv_client_ip",
}, {
in: yobj{
"clients": []yobj{{"ip": "127.0.0.1", "mac": 1}},
"clients": yarr{yobj{"ip": "127.0.0.1", "mac": 1}},
},
want: yobj{
"clients": []yobj{{"ip": "127.0.0.1", "mac": 1}},
"clients": yarr{yobj{"ip": "127.0.0.1", "mac": 1}},
"schema_version": newSchemaVer,
},
wantErr: "client.mac is not a string: 1",
wantErr: `client at index 0: unexpected type of "mac": int`,
name: "inv_client_mac",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema5to6(tc.in)
err := migrateTo6(tc.in)
testutil.AssertErrorMsg(t, tc.wantErr, err)
assert.Equal(t, tc.want, tc.in)
})
@@ -166,7 +170,7 @@ func TestUpgradeSchema7to8(t *testing.T) {
"schema_version": 7,
}
err := upgradeSchema7to8(oldConf)
err := migrateTo8(oldConf)
require.NoError(t, err)
require.Equal(t, oldConf["schema_version"], 8)
@@ -194,7 +198,7 @@ func TestUpgradeSchema8to9(t *testing.T) {
"schema_version": 8,
}
err := upgradeSchema8to9(oldConf)
err := migrateTo9(oldConf)
require.NoError(t, err)
require.Equal(t, oldConf["schema_version"], 9)
@@ -217,7 +221,7 @@ func TestUpgradeSchema8to9(t *testing.T) {
"schema_version": 8,
}
err := upgradeSchema8to9(oldConf)
err := migrateTo9(oldConf)
require.NoError(t, err)
require.Equal(t, oldConf["schema_version"], 9)
@@ -404,12 +408,12 @@ func TestUpgradeSchema9to10(t *testing.T) {
}, {
ups: ultimateAns,
want: nil,
wantErr: "unexpected type of dns.upstream_dns: int",
wantErr: `unexpected type of "upstream_dns": int`,
name: "bad_yarr_type",
}, {
ups: yarr{ultimateAns},
want: nil,
wantErr: "unexpected type of upstream field: int",
wantErr: `unexpected type of upstream field: int`,
name: "bad_upstream_type",
}}
@@ -421,7 +425,7 @@ func TestUpgradeSchema9to10(t *testing.T) {
"schema_version": 9,
}
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema9to10(conf)
err := migrateTo10(conf)
if tc.wantErr != "" {
testutil.AssertErrorMsg(t, tc.wantErr, err)
@@ -446,17 +450,17 @@ func TestUpgradeSchema9to10(t *testing.T) {
}
t.Run("no_dns", func(t *testing.T) {
err := upgradeSchema9to10(yobj{})
err := migrateTo10(yobj{})
assert.NoError(t, err)
})
t.Run("bad_dns", func(t *testing.T) {
err := upgradeSchema9to10(yobj{
err := migrateTo10(yobj{
"dns": ultimateAns,
})
testutil.AssertErrorMsg(t, "unexpected type of dns: int", err)
testutil.AssertErrorMsg(t, `unexpected type of "dns": int`, err)
})
}
@@ -464,7 +468,7 @@ func TestUpgradeSchema10to11(t *testing.T) {
check := func(t *testing.T, conf yobj) {
rlimit, _ := conf["rlimit_nofile"].(int)
err := upgradeSchema10to11(conf)
err := migrateTo11(conf)
require.NoError(t, err)
require.Equal(t, conf["schema_version"], 11)
@@ -521,7 +525,7 @@ func TestUpgradeSchema11to12(t *testing.T) {
}, {
ivl: 0.25,
want: 0,
wantErr: "unexpected type of querylog_interval: float64",
wantErr: `unexpected type of "querylog_interval": float64`,
name: "fail",
}}
@@ -533,7 +537,7 @@ func TestUpgradeSchema11to12(t *testing.T) {
"schema_version": 11,
}
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema11to12(conf)
err := migrateTo12(conf)
if tc.wantErr != "" {
require.Error(t, err)
@@ -562,17 +566,17 @@ func TestUpgradeSchema11to12(t *testing.T) {
}
t.Run("no_dns", func(t *testing.T) {
err := upgradeSchema11to12(yobj{})
err := migrateTo12(yobj{})
assert.NoError(t, err)
})
t.Run("bad_dns", func(t *testing.T) {
err := upgradeSchema11to12(yobj{
err := migrateTo12(yobj{
"dns": 0,
})
testutil.AssertErrorMsg(t, "unexpected type of dns: int", err)
testutil.AssertErrorMsg(t, `unexpected type of "dns": int`, err)
})
t.Run("no_field", func(t *testing.T) {
@@ -580,7 +584,7 @@ func TestUpgradeSchema11to12(t *testing.T) {
"dns": yobj{},
}
err := upgradeSchema11to12(conf)
err := migrateTo12(conf)
require.NoError(t, err)
dns, ok := conf["dns"]
@@ -640,7 +644,7 @@ func TestUpgradeSchema12to13(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema12to13(tc.in)
err := migrateTo13(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -651,10 +655,10 @@ func TestUpgradeSchema12to13(t *testing.T) {
func TestUpgradeSchema13to14(t *testing.T) {
const newSchemaVer = 14
testClient := &clientObject{
Name: "agh-client",
IDs: []string{"id1"},
UseGlobalSettings: true,
testClient := yobj{
"name": "agh-client",
"ids": []string{"id1"},
"use_global_settings": true,
}
testCases := []struct {
@@ -668,37 +672,37 @@ func TestUpgradeSchema13to14(t *testing.T) {
// The clients field will be added anyway.
"clients": yobj{
"persistent": yarr{},
"runtime_sources": &clientSourcesConfig{
WHOIS: true,
ARP: true,
RDNS: false,
DHCP: true,
HostsFile: true,
"runtime_sources": yobj{
"whois": true,
"arp": true,
"rdns": false,
"dhcp": true,
"hosts": true,
},
},
},
name: "no_clients",
}, {
in: yobj{
"clients": []*clientObject{testClient},
"clients": yarr{testClient},
},
want: yobj{
"schema_version": newSchemaVer,
"clients": yobj{
"persistent": []*clientObject{testClient},
"runtime_sources": &clientSourcesConfig{
WHOIS: true,
ARP: true,
RDNS: false,
DHCP: true,
HostsFile: true,
"persistent": yarr{testClient},
"runtime_sources": yobj{
"whois": true,
"arp": true,
"rdns": false,
"dhcp": true,
"hosts": true,
},
},
},
name: "no_dns",
}, {
in: yobj{
"clients": []*clientObject{testClient},
"clients": yarr{testClient},
"dns": yobj{
"resolve_clients": true,
},
@@ -706,13 +710,13 @@ func TestUpgradeSchema13to14(t *testing.T) {
want: yobj{
"schema_version": newSchemaVer,
"clients": yobj{
"persistent": []*clientObject{testClient},
"runtime_sources": &clientSourcesConfig{
WHOIS: true,
ARP: true,
RDNS: true,
DHCP: true,
HostsFile: true,
"persistent": yarr{testClient},
"runtime_sources": yobj{
"whois": true,
"arp": true,
"rdns": true,
"dhcp": true,
"hosts": true,
},
},
"dns": yobj{},
@@ -722,7 +726,7 @@ func TestUpgradeSchema13to14(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema13to14(tc.in)
err := migrateTo14(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -770,7 +774,7 @@ func TestUpgradeSchema14to15(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema14to15(tc.in)
err := migrateTo15(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -829,7 +833,7 @@ func TestUpgradeSchema15to16(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema15to16(tc.in)
err := migrateTo16(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -890,7 +894,7 @@ func TestUpgradeSchema16to17(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema16to17(tc.in)
err := migrateTo17(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -949,7 +953,7 @@ func TestUpgradeSchema17to18(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema17to18(tc.in)
err := migrateTo18(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -962,7 +966,7 @@ func TestUpgradeSchema18to19(t *testing.T) {
defaultWantObj := yobj{
"clients": yobj{
"persistent": []yobj{{
"persistent": yarr{yobj{
"name": "localhost",
"safe_search": yobj{
"enabled": true,
@@ -994,7 +998,7 @@ func TestUpgradeSchema18to19(t *testing.T) {
}, {
in: yobj{
"clients": yobj{
"persistent": []yobj{{"name": "localhost"}},
"persistent": yarr{yobj{"name": "localhost"}},
},
},
want: defaultWantObj,
@@ -1002,7 +1006,7 @@ func TestUpgradeSchema18to19(t *testing.T) {
}, {
in: yobj{
"clients": yobj{
"persistent": []yobj{{"name": "localhost", "safesearch_enabled": true}},
"persistent": yarr{yobj{"name": "localhost", "safesearch_enabled": true}},
},
},
want: defaultWantObj,
@@ -1010,11 +1014,11 @@ func TestUpgradeSchema18to19(t *testing.T) {
}, {
in: yobj{
"clients": yobj{
"persistent": []yobj{{"name": "localhost", "safesearch_enabled": false}},
"persistent": yarr{yobj{"name": "localhost", "safesearch_enabled": false}},
},
},
want: yobj{
"clients": yobj{"persistent": []yobj{{
"clients": yobj{"persistent": yarr{yobj{
"name": "localhost",
"safe_search": yobj{
"enabled": false,
@@ -1033,7 +1037,7 @@ func TestUpgradeSchema18to19(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema18to19(tc.in)
err := migrateTo19(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -1060,7 +1064,7 @@ func TestUpgradeSchema19to20(t *testing.T) {
}, {
ivl: 0.25,
want: 0,
wantErr: "unexpected type of interval: float64",
wantErr: `unexpected type of "interval": float64`,
name: "fail",
}}
@@ -1072,7 +1076,7 @@ func TestUpgradeSchema19to20(t *testing.T) {
"schema_version": 19,
}
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema19to20(conf)
err := migrateTo20(conf)
if tc.wantErr != "" {
require.Error(t, err)
@@ -1101,17 +1105,17 @@ func TestUpgradeSchema19to20(t *testing.T) {
}
t.Run("no_stats", func(t *testing.T) {
err := upgradeSchema19to20(yobj{})
err := migrateTo20(yobj{})
assert.NoError(t, err)
})
t.Run("bad_stats", func(t *testing.T) {
err := upgradeSchema19to20(yobj{
err := migrateTo20(yobj{
"statistics": 0,
})
testutil.AssertErrorMsg(t, "unexpected type of stats: int", err)
testutil.AssertErrorMsg(t, `unexpected type of "statistics": int`, err)
})
t.Run("no_field", func(t *testing.T) {
@@ -1119,7 +1123,7 @@ func TestUpgradeSchema19to20(t *testing.T) {
"statistics": yobj{},
}
err := upgradeSchema19to20(conf)
err := migrateTo20(conf)
require.NoError(t, err)
statsVal, ok := conf["statistics"]
@@ -1176,7 +1180,7 @@ func TestUpgradeSchema20to21(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema20to21(tc.in)
err := migrateTo21(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -1246,7 +1250,7 @@ func TestUpgradeSchema21to22(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema21to22(tc.in)
err := migrateTo22(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -1299,7 +1303,7 @@ func TestUpgradeSchema22to23(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema22to23(tc.in)
err := migrateTo23(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
@@ -1358,24 +1362,287 @@ func TestUpgradeSchema23to24(t *testing.T) {
"verbose": true,
},
want: yobj{
"log_file": "/test/path.log",
"log_max_backups": 1,
"log_max_size": 2,
"log_max_age": 3,
"log_compress": "",
"log_localtime": true,
"verbose": true,
"schema_version": newSchemaVer,
"log_compress": "",
"schema_version": newSchemaVer,
},
wantErrMsg: "unexpected type of log_compress: string",
wantErrMsg: `unexpected type of "log_compress": string`,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema23to24(tc.in)
err := migrateTo24(tc.in)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema24to25(t *testing.T) {
const newSchemaVer = 25
testCases := []struct {
in yobj
want yobj
name string
wantErrMsg string
}{{
name: "empty",
in: yobj{},
want: yobj{
"schema_version": newSchemaVer,
},
wantErrMsg: "",
}, {
name: "ok",
in: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
},
"debug_pprof": true,
},
want: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
"pprof": yobj{
"enabled": true,
"port": 6060,
},
},
"schema_version": newSchemaVer,
},
wantErrMsg: "",
}, {
name: "ok_disabled",
in: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
},
"debug_pprof": false,
},
want: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
"pprof": yobj{
"enabled": false,
"port": 6060,
},
},
"schema_version": newSchemaVer,
},
wantErrMsg: "",
}, {
name: "invalid",
in: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
},
"debug_pprof": 1,
},
want: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
},
"debug_pprof": 1,
"schema_version": newSchemaVer,
},
wantErrMsg: `unexpected type of "debug_pprof": int`,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := migrateTo25(tc.in)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema25to26(t *testing.T) {
const newSchemaVer = 26
testCases := []struct {
in yobj
want yobj
name string
}{{
name: "empty",
in: yobj{},
want: yobj{
"schema_version": newSchemaVer,
},
}, {
name: "ok",
in: yobj{
"dns": yobj{
"filtering_enabled": true,
"filters_update_interval": 24,
"parental_enabled": false,
"safebrowsing_enabled": false,
"safebrowsing_cache_size": 1048576,
"safesearch_cache_size": 1048576,
"parental_cache_size": 1048576,
"safe_search": yobj{
"enabled": false,
"bing": true,
"duckduckgo": true,
"google": true,
"pixabay": true,
"yandex": true,
"youtube": true,
},
"rewrites": yarr{},
"blocked_services": yobj{
"schedule": yobj{
"time_zone": "Local",
},
"ids": yarr{},
},
"protection_enabled": true,
"blocking_mode": "custom_ip",
"blocking_ipv4": "1.2.3.4",
"blocking_ipv6": "1:2:3::4",
"blocked_response_ttl": 10,
"protection_disabled_until": nil,
"parental_block_host": "p.dns.adguard.com",
"safebrowsing_block_host": "s.dns.adguard.com",
},
},
want: yobj{
"dns": yobj{},
"filtering": yobj{
"filtering_enabled": true,
"filters_update_interval": 24,
"parental_enabled": false,
"safebrowsing_enabled": false,
"safebrowsing_cache_size": 1048576,
"safesearch_cache_size": 1048576,
"parental_cache_size": 1048576,
"safe_search": yobj{
"enabled": false,
"bing": true,
"duckduckgo": true,
"google": true,
"pixabay": true,
"yandex": true,
"youtube": true,
},
"rewrites": yarr{},
"blocked_services": yobj{
"schedule": yobj{
"time_zone": "Local",
},
"ids": yarr{},
},
"protection_enabled": true,
"blocking_mode": "custom_ip",
"blocking_ipv4": "1.2.3.4",
"blocking_ipv6": "1:2:3::4",
"blocked_response_ttl": 10,
"protection_disabled_until": nil,
"parental_block_host": "p.dns.adguard.com",
"safebrowsing_block_host": "s.dns.adguard.com",
},
"schema_version": newSchemaVer,
},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := migrateTo26(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema26to27(t *testing.T) {
const newSchemaVer = 27
testCases := []struct {
in yobj
want yobj
name string
}{{
name: "empty",
in: yobj{},
want: yobj{
"schema_version": newSchemaVer,
},
}, {
name: "single_dot",
in: yobj{
"querylog": yobj{
"ignored": yarr{
".",
},
},
"statistics": yobj{
"ignored": yarr{
".",
},
},
},
want: yobj{
"querylog": yobj{
"ignored": yarr{
"|.^",
},
},
"statistics": yobj{
"ignored": yarr{
"|.^",
},
},
"schema_version": newSchemaVer,
},
}, {
name: "mixed",
in: yobj{
"querylog": yobj{
"ignored": yarr{
".",
"example.com",
},
},
"statistics": yobj{
"ignored": yarr{
".",
"example.org",
},
},
},
want: yobj{
"querylog": yobj{
"ignored": yarr{
"|.^",
"example.com",
},
},
"statistics": yobj{
"ignored": yarr{
"|.^",
"example.org",
},
},
"schema_version": newSchemaVer,
},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := migrateTo27(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}

View File

@@ -0,0 +1,140 @@
// Package confmigrate provides a way to upgrade the YAML configuration file.
package confmigrate
import (
"bytes"
"fmt"
"github.com/AdguardTeam/golibs/log"
yaml "gopkg.in/yaml.v3"
)
// LastSchemaVersion is the most recent schema version.
const LastSchemaVersion uint = 27
// Config is a the configuration for initializing a [Migrator].
type Config struct {
// WorkingDir is an absolute path to the working directory of AdGuardHome.
WorkingDir string
}
// Migrator performs the YAML configuration file migrations.
type Migrator struct {
// workingDir is an absolute path to the working directory of AdGuardHome.
workingDir string
}
// New creates a new Migrator.
func New(cfg *Config) (m *Migrator) {
return &Migrator{
workingDir: cfg.WorkingDir,
}
}
// Migrate preforms necessary upgrade operations to upgrade file to target
// schema version, if needed. It returns the body of the upgraded config file,
// whether the file was upgraded, and an error, if any. If upgraded is false,
// the body is the same as the input.
func (m *Migrator) Migrate(body []byte, target uint) (newBody []byte, upgraded bool, err error) {
diskConf := yobj{}
err = yaml.Unmarshal(body, &diskConf)
if err != nil {
return body, false, fmt.Errorf("parsing config file for upgrade: %w", err)
}
currentInt, _, err := fieldVal[int](diskConf, "schema_version")
if err != nil {
// Don't wrap the error, since it's informative enough as is.
return body, false, err
}
current := uint(currentInt)
log.Debug("got schema version %v", current)
if err = validateVersion(current, target); err != nil {
// Don't wrap the error, since it's informative enough as is.
return body, false, err
} else if current == target {
return body, false, nil
}
if err = m.upgradeConfigSchema(current, target, diskConf); err != nil {
// Don't wrap the error, since it's informative enough as is.
return body, false, err
}
buf := bytes.NewBuffer(newBody)
enc := yaml.NewEncoder(buf)
enc.SetIndent(2)
if err = enc.Encode(diskConf); err != nil {
return body, false, fmt.Errorf("generating new config: %w", err)
}
return buf.Bytes(), true, nil
}
// validateVersion validates the current and desired schema versions.
func validateVersion(current, target uint) (err error) {
switch {
case current > target:
return fmt.Errorf("unknown current schema version %d", current)
case target > LastSchemaVersion:
return fmt.Errorf("unknown target schema version %d", target)
case target < current:
return fmt.Errorf("target schema version %d lower than current %d", target, current)
default:
return nil
}
}
// migrateFunc is a function that upgrades a config and returns an error.
type migrateFunc = func(diskConf yobj) (err error)
// upgradeConfigSchema upgrades the configuration schema in diskConf from
// current to target version. current must be less than target, and both must
// be non-negative and less or equal to [LastSchemaVersion].
func (m *Migrator) upgradeConfigSchema(current, target uint, diskConf yobj) (err error) {
upgrades := [LastSchemaVersion]migrateFunc{
0: m.migrateTo1,
1: m.migrateTo2,
2: migrateTo3,
3: migrateTo4,
4: migrateTo5,
5: migrateTo6,
6: migrateTo7,
7: migrateTo8,
8: migrateTo9,
9: migrateTo10,
10: migrateTo11,
11: migrateTo12,
12: migrateTo13,
13: migrateTo14,
14: migrateTo15,
15: migrateTo16,
16: migrateTo17,
17: migrateTo18,
18: migrateTo19,
19: migrateTo20,
20: migrateTo21,
21: migrateTo22,
22: migrateTo23,
23: migrateTo24,
24: migrateTo25,
25: migrateTo26,
26: migrateTo27,
}
for i, migrate := range upgrades[current:target] {
cur := current + uint(i)
next := current + uint(i) + 1
log.Printf("Upgrade yaml: %d to %d", cur, next)
if err = migrate(diskConf); err != nil {
return fmt.Errorf("migrating schema %d to %d: %w", cur, next, err)
}
}
return nil
}

View File

@@ -0,0 +1,208 @@
package confmigrate_test
import (
"io/fs"
"os"
"path/filepath"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/confmigrate"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/bcrypt"
yaml "gopkg.in/yaml.v3"
)
// getField returns the value located at the given indexes in the given object.
// It fails the test if the value is not found or of the expected type. The
// indexes can be either strings or integers, and are interpreted as map keys or
// array indexes, respectively.
func getField[T any](t require.TestingT, obj any, indexes ...any) (val T) {
for _, index := range indexes {
switch index := index.(type) {
case string:
require.IsType(t, map[string]any(nil), obj)
typedObj := obj.(map[string]any)
require.Contains(t, typedObj, index)
obj = typedObj[index]
case int:
require.IsType(t, []any(nil), obj)
typedObj := obj.([]any)
require.Less(t, index, len(typedObj))
obj = typedObj[index]
default:
t.Errorf("unexpected index type: %T", index)
t.FailNow()
}
}
require.IsType(t, val, obj)
return obj.(T)
}
// testdata is a virtual filesystem containing test data.
var testdata = os.DirFS("testdata")
func TestMigrateConfig_Migrate(t *testing.T) {
const (
inputFileName = "input.yml"
outputFileName = "output.yml"
)
testCases := []struct {
yamlEqFunc func(t require.TestingT, expected, actual string, msgAndArgs ...any)
name string
targetVersion uint
}{{
yamlEqFunc: require.YAMLEq,
name: "v1",
targetVersion: 1,
}, {
yamlEqFunc: require.YAMLEq,
name: "v2",
targetVersion: 2,
}, {
yamlEqFunc: require.YAMLEq,
name: "v3",
targetVersion: 3,
}, {
yamlEqFunc: require.YAMLEq,
name: "v4",
targetVersion: 4,
}, {
// Compare passwords separately because bcrypt hashes those with a
// different salt every time.
yamlEqFunc: func(t require.TestingT, expected, actual string, msgAndArgs ...any) {
if h, ok := t.(interface{ Helper() }); ok {
h.Helper()
}
var want, got map[string]any
err := yaml.Unmarshal([]byte(expected), &want)
require.NoError(t, err)
err = yaml.Unmarshal([]byte(actual), &got)
require.NoError(t, err)
gotPass := getField[string](t, got, "users", 0, "password")
wantPass := getField[string](t, want, "users", 0, "password")
require.NoError(t, bcrypt.CompareHashAndPassword([]byte(gotPass), []byte(wantPass)))
delete(getField[map[string]any](t, got, "users", 0), "password")
delete(getField[map[string]any](t, want, "users", 0), "password")
require.Equal(t, want, got, msgAndArgs...)
},
name: "v5",
targetVersion: 5,
}, {
yamlEqFunc: require.YAMLEq,
name: "v6",
targetVersion: 6,
}, {
yamlEqFunc: require.YAMLEq,
name: "v7",
targetVersion: 7,
}, {
yamlEqFunc: require.YAMLEq,
name: "v8",
targetVersion: 8,
}, {
yamlEqFunc: require.YAMLEq,
name: "v9",
targetVersion: 9,
}, {
yamlEqFunc: require.YAMLEq,
name: "v10",
targetVersion: 10,
}, {
yamlEqFunc: require.YAMLEq,
name: "v11",
targetVersion: 11,
}, {
yamlEqFunc: require.YAMLEq,
name: "v12",
targetVersion: 12,
}, {
yamlEqFunc: require.YAMLEq,
name: "v13",
targetVersion: 13,
}, {
yamlEqFunc: require.YAMLEq,
name: "v14",
targetVersion: 14,
}, {
yamlEqFunc: require.YAMLEq,
name: "v15",
targetVersion: 15,
}, {
yamlEqFunc: require.YAMLEq,
name: "v16",
targetVersion: 16,
}, {
yamlEqFunc: require.YAMLEq,
name: "v17",
targetVersion: 17,
}, {
yamlEqFunc: require.YAMLEq,
name: "v18",
targetVersion: 18,
}, {
yamlEqFunc: require.YAMLEq,
name: "v19",
targetVersion: 19,
}, {
yamlEqFunc: require.YAMLEq,
name: "v20",
targetVersion: 20,
}, {
yamlEqFunc: require.YAMLEq,
name: "v21",
targetVersion: 21,
}, {
yamlEqFunc: require.YAMLEq,
name: "v22",
targetVersion: 22,
}, {
yamlEqFunc: require.YAMLEq,
name: "v23",
targetVersion: 23,
}, {
yamlEqFunc: require.YAMLEq,
name: "v24",
targetVersion: 24,
}, {
yamlEqFunc: require.YAMLEq,
name: "v25",
targetVersion: 25,
}, {
yamlEqFunc: require.YAMLEq,
name: "v26",
targetVersion: 26,
}, {
yamlEqFunc: require.YAMLEq,
name: "v27",
targetVersion: 27,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
body, err := fs.ReadFile(testdata, filepath.Join(t.Name(), inputFileName))
require.NoError(t, err)
wantBody, err := fs.ReadFile(testdata, filepath.Join(t.Name(), outputFileName))
require.NoError(t, err)
migrator := confmigrate.New(&confmigrate.Config{
WorkingDir: t.Name(),
})
newBody, upgraded, err := migrator.Migrate(body, tc.targetVersion)
require.NoError(t, err)
require.True(t, upgraded)
tc.yamlEqFunc(t, string(wantBody), string(newBody))
})
}
}

View File

@@ -0,0 +1,31 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
coredns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
user_rules: []

View File

@@ -0,0 +1,32 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
coredns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
schema_version: 1
user_rules: []

View File

@@ -0,0 +1,60 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
local_domain_name: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 9
user_rules: []

View File

@@ -0,0 +1,60 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
local_domain_name: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 10
user_rules: []

View File

@@ -0,0 +1,61 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
local_domain_name: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 10
user_rules: []
rlimit_nofile: 123

View File

@@ -0,0 +1,64 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
local_domain_name: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 11
user_rules: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,65 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
local_domain_name: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
querylog_interval: 30
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 11
user_rules: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,65 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
local_domain_name: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
querylog_interval: 720h
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 12
user_rules: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,65 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
local_domain_name: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
querylog_interval: 720h
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 12
user_rules: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,65 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
querylog_interval: 720h
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 13
user_rules: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,66 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
querylog_interval: 720h
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
resolve_clients: true
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 13
user_rules: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,72 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
querylog_interval: 720h
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 14
user_rules: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,74 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
querylog_file_enabled: true
querylog_interval: 720h
querylog_size_memory: 1000
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 14
user_rules: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,76 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 15
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,77 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
statistics_interval: 10
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 15
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,80 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 16
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 10
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,81 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet: true
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 16
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 10
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,84 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 17
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 10
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,84 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 17
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 10
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,91 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 18
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 10
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,91 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: true
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 18
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 10
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,98 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 19
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 10
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,34 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
coredns:
bind_host: 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns: 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
schema_version: 1
user_rules: []

View File

@@ -0,0 +1,34 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
dns:
bind_host: 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns: 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
schema_version: 2
user_rules: []

View File

@@ -0,0 +1,98 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 19
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 10
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,98 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 20
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,100 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 20
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,103 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 21
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,105 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 21
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,108 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 22
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,109 @@
bind_host: 127.0.0.1
bind_port: 3000
web_session_ttl: 3
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 22
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,109 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 23
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''

View File

@@ -0,0 +1,116 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 23
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ""
rlimit_nofile: 123
user: ""
log_file: ""
log_max_backups: 0
log_max_size: 100
log_max_age: 3
log_compress: true
log_localtime: false
verbose: true

View File

@@ -0,0 +1,117 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 24
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -0,0 +1,118 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
debug_pprof: true
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 24
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -0,0 +1,120 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
pprof:
enabled: true
port: 6060
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 25
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -0,0 +1,120 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
pprof:
enabled: true
port: 6060
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 25
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -0,0 +1,121 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
pprof:
enabled: true
port: 6060
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
parental_sensitivity: 0
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filtering:
filtering_enabled: true
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
protection_enabled: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
blocked_response_ttl: 10
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 26
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored: []
statistics:
enabled: true
interval: 240h
ignored: []
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -0,0 +1,123 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
pprof:
enabled: true
port: 6060
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
parental_sensitivity: 0
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filtering:
filtering_enabled: true
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
protection_enabled: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
blocked_response_ttl: 10
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 26
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored:
- '.'
statistics:
enabled: true
interval: 240h
ignored:
- '.'
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -0,0 +1,123 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
pprof:
enabled: true
port: 6060
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
parental_sensitivity: 0
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filtering:
filtering_enabled: true
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
protection_enabled: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
blocked_response_ttl: 10
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 27
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored:
- '|.^'
statistics:
enabled: true
interval: 240h
ignored:
- '|.^'
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -0,0 +1,33 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns: 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
schema_version: 2
user_rules: []

View File

@@ -0,0 +1,34 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
schema_version: 3
user_rules: []

View File

@@ -0,0 +1,43 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ip: 127.0.0.1
mac: ""
use_global_settings: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
schema_version: 3
user_rules: []

View File

@@ -0,0 +1,44 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ip: 127.0.0.1
mac: ""
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
schema_version: 4
user_rules: []

View File

@@ -0,0 +1,44 @@
bind_host: 127.0.0.1
bind_port: 3000
auth_name: testuser
auth_pass: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ip: 127.0.0.1
mac: ""
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
schema_version: 4
user_rules: []

View File

@@ -0,0 +1,45 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ip: 127.0.0.1
mac: ""
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
schema_version: 5
user_rules: []

View File

@@ -0,0 +1,45 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ip: 127.0.0.1
mac: aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
schema_version: 5
user_rules: []

View File

@@ -0,0 +1,48 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
ip: 127.0.0.1
mac: aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
schema_version: 6
user_rules: []

View File

@@ -0,0 +1,53 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 6
user_rules: []

View File

@@ -0,0 +1,54 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 7
user_rules: []

View File

@@ -0,0 +1,57 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_host: 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 7
user_rules: []

View File

@@ -0,0 +1,58 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 8
user_rules: []

View File

@@ -0,0 +1,59 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
autohost_tld: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 8
user_rules: []

View File

@@ -0,0 +1,59 @@
bind_host: 127.0.0.1
bind_port: 3000
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
local_domain_name: local
protection_enabled: true
filtering_enabled: true
safebrowsing_enabled: false
safesearch_enabled: false
parental_enabled: false
parental_sensitivity: 0
blocked_response_ttl: 10
querylog_enabled: true
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
bootstrap_dns:
- 8.8.8.8:53
filters:
- url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: ""
enabled: true
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
enabled: false
- url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
enabled: false
clients:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safesearch_enabled: false
dhcp:
enabled: false
interface_name: vboxnet0
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 9
user_rules: []

View File

@@ -0,0 +1,35 @@
package confmigrate
import (
"os"
"path/filepath"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
)
// migrateTo1 performs the following changes:
//
// # BEFORE:
// # …
//
// # AFTER:
// 'schema_version': 1
// # …
//
// It also deletes the unused dnsfilter.txt file, since the following versions
// store filters in data/filters/.
func (m *Migrator) migrateTo1(diskConf yobj) (err error) {
diskConf["schema_version"] = 1
dnsFilterPath := filepath.Join(m.workingDir, "dnsfilter.txt")
log.Printf("deleting %s as we don't need it anymore", dnsFilterPath)
err = os.Remove(dnsFilterPath)
if err != nil && !errors.Is(err, os.ErrNotExist) {
log.Info("warning: %s", err)
// Go on.
}
return nil
}

118
internal/confmigrate/v10.go Normal file
View File

@@ -0,0 +1,118 @@
package confmigrate
import (
"fmt"
"net/url"
"strconv"
"strings"
"github.com/AdguardTeam/golibs/netutil"
)
// migrateTo10 performs the following changes:
//
// # BEFORE:
// 'schema_version': 9
// 'dns':
// 'upstream_dns':
// - 'quic://some-upstream.com'
// 'local_ptr_upstreams':
// - 'quic://some-upstream.com'
// # …
// # …
//
// # AFTER:
// 'schema_version': 10
// 'dns':
// 'upstream_dns':
// - 'quic://some-upstream.com:784'
// 'local_ptr_upstreams':
// - 'quic://some-upstream.com:784'
// # …
// # …
func migrateTo10(diskConf yobj) (err error) {
diskConf["schema_version"] = 10
dns, ok, err := fieldVal[yobj](diskConf, "dns")
if !ok {
return err
}
const quicPort = 784
ups, ok, err := fieldVal[yarr](dns, "upstream_dns")
if err != nil {
return err
} else if ok {
if err = addQUICPorts(ups, quicPort); err != nil {
return err
}
dns["upstream_dns"] = ups
}
ups, ok, err = fieldVal[yarr](dns, "local_ptr_upstreams")
if err != nil {
return err
} else if ok {
if err = addQUICPorts(ups, quicPort); err != nil {
return err
}
dns["local_ptr_upstreams"] = ups
}
return nil
}
// addQUICPorts inserts a port into each QUIC upstream's hostname in ups if
// those are missing.
func addQUICPorts(ups yarr, port int) (err error) {
for i, uVal := range ups {
u, ok := uVal.(string)
if !ok {
return fmt.Errorf("unexpected type of upstream field: %T", uVal)
}
ups[i] = addQUICPort(u, port)
}
return nil
}
// addQUICPort inserts a port into QUIC upstream's hostname if it is missing.
func addQUICPort(ups string, port int) (withPort string) {
if ups == "" || ups[0] == '#' {
return ups
}
var doms string
withPort = ups
if strings.HasPrefix(ups, "[/") {
domsAndUps := strings.Split(strings.TrimPrefix(ups, "[/"), "/]")
if len(domsAndUps) != 2 {
return ups
}
doms, withPort = "[/"+domsAndUps[0]+"/]", domsAndUps[1]
}
if !strings.Contains(withPort, "://") {
return ups
}
upsURL, err := url.Parse(withPort)
if err != nil || upsURL.Scheme != "quic" {
return ups
}
var host string
host, err = netutil.SplitHost(upsURL.Host)
if err != nil || host != upsURL.Host {
return ups
}
upsURL.Host = strings.Join([]string{host, strconv.Itoa(port)}, ":")
return doms + upsURL.String()
}

View File

@@ -0,0 +1,33 @@
package confmigrate
// migrateTo11 performs the following changes:
//
// # BEFORE:
// 'schema_version': 10
// 'rlimit_nofile': 42
// # …
//
// # AFTER:
// 'schema_version': 11
// 'os':
// 'group': ''
// 'rlimit_nofile': 42
// 'user': ''
// # …
func migrateTo11(diskConf yobj) (err error) {
diskConf["schema_version"] = 11
rlimit, _, err := fieldVal[int](diskConf, "rlimit_nofile")
if err != nil {
return err
}
delete(diskConf, "rlimit_nofile")
diskConf["os"] = yobj{
"group": "",
"rlimit_nofile": rlimit,
"user": "",
}
return nil
}

View File

@@ -0,0 +1,43 @@
package confmigrate
import (
"time"
"github.com/AdguardTeam/golibs/timeutil"
)
// migrateTo12 performs the following changes:
//
// # BEFORE:
// 'schema_version': 11
// 'querylog_interval': 90
// # …
//
// # AFTER:
// 'schema_version': 12
// 'querylog_interval': '2160h'
// # …
func migrateTo12(diskConf yobj) (err error) {
diskConf["schema_version"] = 12
dns, ok, err := fieldVal[yobj](diskConf, "dns")
if !ok {
return err
}
const field = "querylog_interval"
qlogIvl, ok, err := fieldVal[int](dns, field)
if !ok {
if err != nil {
return err
}
// Set the initial value from home.initConfig function.
qlogIvl = 90
}
dns[field] = timeutil.Duration{Duration: time.Duration(qlogIvl) * timeutil.Day}
return nil
}

View File

@@ -0,0 +1,32 @@
package confmigrate
// migrateTo13 performs the following changes:
//
// # BEFORE:
// 'schema_version': 12
// 'dns':
// 'local_domain_name': 'lan'
// # …
// # …
//
// # AFTER:
// 'schema_version': 13
// 'dhcp':
// 'local_domain_name': 'lan'
// # …
// # …
func migrateTo13(diskConf yobj) (err error) {
diskConf["schema_version"] = 13
dns, ok, err := fieldVal[yobj](diskConf, "dns")
if !ok {
return err
}
dhcp, ok, err := fieldVal[yobj](diskConf, "dhcp")
if !ok {
return err
}
return moveSameVal[string](dns, dhcp, "local_domain_name")
}

View File

@@ -0,0 +1,62 @@
package confmigrate
// migrateTo14 performs the following changes:
//
// # BEFORE:
// 'schema_version': 13
// 'dns':
// 'resolve_clients': true
// # …
// 'clients':
// - 'name': 'client-name'
// # …
// # …
//
// # AFTER:
// 'schema_version': 14
// 'dns':
// # …
// 'clients':
// 'persistent':
// - 'name': 'client-name'
// # …
// 'runtime_sources':
// 'whois': true
// 'arp': true
// 'rdns': true
// 'dhcp': true
// 'hosts': true
// # …
func migrateTo14(diskConf yobj) (err error) {
diskConf["schema_version"] = 14
persistent, ok, err := fieldVal[yarr](diskConf, "clients")
if !ok {
if err != nil {
return err
}
persistent = yarr{}
}
runtimeClients := yobj{
"whois": true,
"arp": true,
"rdns": false,
"dhcp": true,
"hosts": true,
}
diskConf["clients"] = yobj{
"persistent": persistent,
"runtime_sources": runtimeClients,
}
dns, ok, err := fieldVal[yobj](diskConf, "dns")
if err != nil {
return err
} else if !ok {
return nil
}
return moveVal[bool](dns, runtimeClients, "resolve_clients", "rdns")
}

View File

@@ -0,0 +1,52 @@
package confmigrate
// migrateTo15 performs the following changes:
//
// # BEFORE:
// 'schema_version': 14
// 'dns':
// # …
// 'querylog_enabled': true
// 'querylog_file_enabled': true
// 'querylog_interval': '2160h'
// 'querylog_size_memory': 1000
// 'querylog':
// # …
// # …
//
// # AFTER:
// 'schema_version': 15
// 'dns':
// # …
// 'querylog':
// 'enabled': true
// 'file_enabled': true
// 'interval': '2160h'
// 'size_memory': 1000
// 'ignored': []
// # …
// # …
func migrateTo15(diskConf yobj) (err error) {
diskConf["schema_version"] = 15
dns, ok, err := fieldVal[yobj](diskConf, "dns")
if !ok {
return err
}
qlog := map[string]any{
"ignored": yarr{},
"enabled": true,
"file_enabled": true,
"interval": "2160h",
"size_memory": 1000,
}
diskConf["querylog"] = qlog
return coalesceError(
moveVal[bool](dns, qlog, "querylog_enabled", "enabled"),
moveVal[bool](dns, qlog, "querylog_file_enabled", "file_enabled"),
moveVal[any](dns, qlog, "querylog_interval", "interval"),
moveVal[int](dns, qlog, "querylog_size_memory", "size_memory"),
)
}

View File

@@ -0,0 +1,78 @@
package confmigrate
// migrateTo16 performs the following changes:
//
// # BEFORE:
// 'schema_version': 15
// 'dns':
// # …
// 'statistics_interval': 1
// 'statistics':
// # …
// # …
//
// # AFTER:
// 'schema_version': 16
// 'dns':
// # …
// 'statistics':
// 'enabled': true
// 'interval': 1
// 'ignored': []
// # …
// # …
//
// If statistics were disabled:
//
// # BEFORE:
// 'schema_version': 15
// 'dns':
// # …
// 'statistics_interval': 0
// 'statistics':
// # …
// # …
//
// # AFTER:
// 'schema_version': 16
// 'dns':
// # …
// 'statistics':
// 'enabled': false
// 'interval': 1
// 'ignored': []
// # …
// # …
func migrateTo16(diskConf yobj) (err error) {
diskConf["schema_version"] = 16
dns, ok, err := fieldVal[yobj](diskConf, "dns")
if !ok {
return err
}
stats := yobj{
"enabled": true,
"interval": 1,
"ignored": yarr{},
}
diskConf["statistics"] = stats
const field = "statistics_interval"
statsIvl, ok, err := fieldVal[int](dns, field)
if !ok {
return err
}
if statsIvl == 0 {
// Set the interval to the default value of one day to make sure
// that it passes the validations.
stats["enabled"] = false
} else {
stats["interval"] = statsIvl
}
delete(dns, field)
return nil
}

View File

@@ -0,0 +1,39 @@
package confmigrate
// migrateTo17 performs the following changes:
//
// # BEFORE:
// 'schema_version': 16
// 'dns':
// 'edns_client_subnet': false
// # …
// # …
//
// # AFTER:
// 'schema_version': 17
// 'dns':
// 'edns_client_subnet':
// 'enabled': false
// 'use_custom': false
// 'custom_ip': ""
// # …
// # …
func migrateTo17(diskConf yobj) (err error) {
diskConf["schema_version"] = 17
dns, ok, err := fieldVal[yobj](diskConf, "dns")
if !ok {
return err
}
const field = "edns_client_subnet"
enabled, _, _ := fieldVal[bool](dns, field)
dns[field] = yobj{
"enabled": enabled,
"use_custom": false,
"custom_ip": "",
}
return nil
}

View File

@@ -0,0 +1,45 @@
package confmigrate
// migrateTo18 performs the following changes:
//
// # BEFORE:
// 'schema_version': 17
// 'dns':
// 'safesearch_enabled': true
// # …
// # …
//
// # AFTER:
// 'schema_version': 18
// 'dns':
// 'safe_search':
// 'enabled': true
// 'bing': true
// 'duckduckgo': true
// 'google': true
// 'pixabay': true
// 'yandex': true
// 'youtube': true
// # …
// # …
func migrateTo18(diskConf yobj) (err error) {
diskConf["schema_version"] = 18
dns, ok, err := fieldVal[yobj](diskConf, "dns")
if !ok {
return err
}
safeSearch := yobj{
"enabled": true,
"bing": true,
"duckduckgo": true,
"google": true,
"pixabay": true,
"yandex": true,
"youtube": true,
}
dns["safe_search"] = safeSearch
return moveVal[bool](dns, safeSearch, "safesearch_enabled", "enabled")
}

View File

@@ -0,0 +1,72 @@
package confmigrate
import "github.com/AdguardTeam/golibs/log"
// migrateTo19 performs the following changes:
//
// # BEFORE:
// 'schema_version': 18
// 'clients':
// 'persistent':
// - 'name': 'client-name'
// 'safesearch_enabled': true
// # …
// # …
// # …
//
// # AFTER:
// 'schema_version': 19
// 'clients':
// 'persistent':
// - 'name': 'client-name'
// 'safe_search':
// 'enabled': true
// 'bing': true
// 'duckduckgo': true
// 'google': true
// 'pixabay': true
// 'yandex': true
// 'youtube': true
// # …
// # …
// # …
func migrateTo19(diskConf yobj) (err error) {
diskConf["schema_version"] = 19
clients, ok, err := fieldVal[yobj](diskConf, "clients")
if !ok {
return err
}
persistent, ok, _ := fieldVal[yarr](clients, "persistent")
if !ok {
return nil
}
for _, p := range persistent {
var c yobj
c, ok = p.(yobj)
if !ok {
continue
}
safeSearch := yobj{
"enabled": true,
"bing": true,
"duckduckgo": true,
"google": true,
"pixabay": true,
"yandex": true,
"youtube": true,
}
err = moveVal[bool](c, safeSearch, "safesearch_enabled", "enabled")
if err != nil {
log.Debug("migrating to version 19: %s", err)
}
c["safe_search"] = safeSearch
}
return nil
}

View File

@@ -0,0 +1,37 @@
package confmigrate
import (
"os"
"path/filepath"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
)
// migrateTo2 performs the following changes:
//
// # BEFORE:
// 'schema_version': 1
// 'coredns':
// # …
//
// # AFTER:
// 'schema_version': 2
// 'dns':
// # …
//
// It also deletes the Corefile file, since it isn't used anymore.
func (m *Migrator) migrateTo2(diskConf yobj) (err error) {
diskConf["schema_version"] = 2
coreFilePath := filepath.Join(m.workingDir, "Corefile")
log.Printf("deleting %s as we don't need it anymore", coreFilePath)
err = os.Remove(coreFilePath)
if err != nil && !errors.Is(err, os.ErrNotExist) {
log.Info("warning: %s", err)
// Go on.
}
return moveVal[any](diskConf, diskConf, "coredns", "dns")
}

View File

@@ -0,0 +1,44 @@
package confmigrate
import (
"time"
"github.com/AdguardTeam/golibs/timeutil"
)
// migrateTo20 performs the following changes:
//
// # BEFORE:
// 'schema_version': 19
// 'statistics':
// 'interval': 1
// # …
// # …
//
// # AFTER:
// 'schema_version': 20
// 'statistics':
// 'interval': 24h
// # …
// # …
func migrateTo20(diskConf yobj) (err error) {
diskConf["schema_version"] = 20
stats, ok, err := fieldVal[yobj](diskConf, "statistics")
if !ok {
return err
}
const field = "interval"
ivl, ok, err := fieldVal[int](stats, field)
if err != nil {
return err
} else if !ok || ivl == 0 {
ivl = 1
}
stats[field] = timeutil.Duration{Duration: time.Duration(ivl) * timeutil.Day}
return nil
}

Some files were not shown because too many files have changed in this diff Show More